packages feed

stan-0.0.0.0: src/Stan/Inspection/Infinite.hs

{- |
Copyright: (c) 2020 Kowainik
SPDX-License-Identifier: MPL-2.0
Maintainer: Kowainik <xrom.xkov@gmail.com>

Contains all 'Inspection's for functions that hang on infinite lists.

The __infinite__ inspections are in ranges:

* @STAN-0101 .. STAN-0200@
-}

module Stan.Inspection.Infinite
    ( -- * Infinite inspections
      -- *** Infinite 'GHC.List.reverse'
      stan0101
      -- *** Infinite 'Data.OldList.isSuffixOf'
    , stan0102
      -- *** Infinite 'Data.Foldable.length'
    , stan0103
      -- *** Infinite 'Data.OldList.genericLength'
    , stan0104
      -- *** Infinite 'Data.Foldable.sum'
    , stan0105
      -- *** Infinite 'Data.Foldable.product'
    , stan0106

      -- * All inspections
    , infiniteInspectionsMap
    ) where

import Relude.Extra.Tuple (fmapToFst)

import Stan.Core.Id (Id (..))
import Stan.Inspection (Inspection (..), InspectionAnalysis (..), InspectionsMap)
import Stan.NameMeta (NameMeta (..), mkBaseFoldableMeta, mkBaseListMeta, mkBaseOldListMeta)
import Stan.Pattern.Ast (namesToPatternAst)
import Stan.Pattern.Edsl (PatternBool (..))
import Stan.Pattern.Type (PatternType (..), listFunPattern)
import Stan.Severity (Severity (..))

import qualified Stan.Category as Category


-- | All infinite 'Inspection's map from 'Id's.
infiniteInspectionsMap :: InspectionsMap
infiniteInspectionsMap = fromList $ fmapToFst inspectionId
    [ stan0101
    , stan0102
    , stan0103
    , stan0104
    , stan0105
    , stan0106
    ]

-- | Smart constructor to create infinite 'Inspection'.
mkInfiniteInspection :: Id Inspection -> NonEmpty (NameMeta, PatternType) -> Inspection
mkInfiniteInspection insId pats@((NameMeta{..},_) :| _) = Inspection
    { inspectionId = insId
    , inspectionName = "Infinite: " <> nameMetaPackage <> "/" <> nameMetaName
    , inspectionDescription =
        "Usage of the '" <> nameMetaName <> "' function that hangs on infinite lists"
    , inspectionSolution =
        [ "Don't use '" <> nameMetaName <> "' if you expect your function to work with infinite lists"
        , "{Extra dependency} Use the 'slist' library for fast and safe functions on infinite lists"
        ]
    , inspectionCategory = Category.infinite :| [Category.list]
    , inspectionSeverity = PotentialBug
    , inspectionAnalysis = FindAst $ namesToPatternAst pats
    }

-- | 'Inspection' for 'stan0101' — infinite 'reverse' @STAN-0101@.
stan0101 :: Inspection
stan0101 = mkInfiniteInspection (Id "STAN-0101") $ one (mkBaseListMeta "reverse", (?))

-- | 'Inspection' for 'stan0102' — infinite 'Data.OldList.isSuffixOf' @STAN-0102@.
stan0102 :: Inspection
stan0102 = mkInfiniteInspection (Id "STAN-0102") $ one (mkBaseOldListMeta "isSuffixOf", (?))

-- | 'Inspection' for 'stan0103' — infinite 'Data.Foldable.length' | 'Data.OldList.length' @STAN-0103@.
stan0103 :: Inspection
stan0103 = mkInfiniteInspection (Id "STAN-0103") $
        (mkBaseFoldableMeta "length", listFunPattern)
    :| [(mkBaseListMeta     "length", listFunPattern)]

-- | 'Inspection' for 'stan0104' — infinite 'Data.OldList.genericLength' @STAN-0104@.
stan0104 :: Inspection
stan0104 = mkInfiniteInspection (Id "STAN-0104") $ one (mkBaseOldListMeta "genericLength", (?))

-- | 'Inspection' for 'stan0105' — infinite 'Data.Foldable.sum' @STAN-0105@.
stan0105 :: Inspection
stan0105 = mkInfiniteInspection (Id "STAN-0105") $ one (mkBaseFoldableMeta "sum", listFunPattern)

-- | 'Inspection' for 'stan0106' — infinite 'Data.Foldable.product' @STAN-0106@.
stan0106 :: Inspection
stan0106 = mkInfiniteInspection (Id "STAN-0106") $ one (mkBaseFoldableMeta "product", listFunPattern)