{- |
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 :: InspectionsMap
infiniteInspectionsMap = [Item InspectionsMap] -> InspectionsMap
forall l. IsList l => [Item l] -> l
fromList ([Item InspectionsMap] -> InspectionsMap)
-> [Item InspectionsMap] -> InspectionsMap
forall a b. (a -> b) -> a -> b
$ (Inspection -> Id Inspection)
-> [Inspection] -> [(Id Inspection, Inspection)]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f (b, a)
fmapToFst Inspection -> Id Inspection
inspectionId
    [ Inspection
stan0101
    , Inspection
stan0102
    , Inspection
stan0103
    , Inspection
stan0104
    , Inspection
stan0105
    , Inspection
stan0106
    ]

-- | Smart constructor to create infinite 'Inspection'.
mkInfiniteInspection :: Id Inspection -> NonEmpty (NameMeta, PatternType) -> Inspection
mkInfiniteInspection :: Id Inspection -> NonEmpty (NameMeta, PatternType) -> Inspection
mkInfiniteInspection insId :: Id Inspection
insId pats :: NonEmpty (NameMeta, PatternType)
pats@((NameMeta{..},_) :| _) = $WInspection :: Id Inspection
-> Text
-> Text
-> [Text]
-> NonEmpty Category
-> Severity
-> InspectionAnalysis
-> Inspection
Inspection
    { inspectionId :: Id Inspection
inspectionId = Id Inspection
insId
    , inspectionName :: Text
inspectionName = "Infinite: " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
nameMetaPackage Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> "/" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
nameMetaName
    , inspectionDescription :: Text
inspectionDescription =
        "Usage of the '" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
nameMetaName Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> "' function that hangs on infinite lists"
    , inspectionSolution :: [Text]
inspectionSolution =
        [ "Don't use '" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
nameMetaName Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> "' 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 :: NonEmpty Category
inspectionCategory = Category
Category.infinite Category -> [Category] -> NonEmpty Category
forall a. a -> [a] -> NonEmpty a
:| [Category
Category.list]
    , inspectionSeverity :: Severity
inspectionSeverity = Severity
PotentialBug
    , inspectionAnalysis :: InspectionAnalysis
inspectionAnalysis = PatternAst -> InspectionAnalysis
FindAst (PatternAst -> InspectionAnalysis)
-> PatternAst -> InspectionAnalysis
forall a b. (a -> b) -> a -> b
$ NonEmpty (NameMeta, PatternType) -> PatternAst
namesToPatternAst NonEmpty (NameMeta, PatternType)
pats
    }

-- | 'Inspection' for 'stan0101' — infinite 'reverse' @STAN-0101@.
stan0101 :: Inspection
stan0101 :: Inspection
stan0101 = Id Inspection -> NonEmpty (NameMeta, PatternType) -> Inspection
mkInfiniteInspection (Text -> Id Inspection
forall a. Text -> Id a
Id "STAN-0101") (NonEmpty (NameMeta, PatternType) -> Inspection)
-> NonEmpty (NameMeta, PatternType) -> Inspection
forall a b. (a -> b) -> a -> b
$ OneItem (NonEmpty (NameMeta, PatternType))
-> NonEmpty (NameMeta, PatternType)
forall x. One x => OneItem x -> x
one (Text -> NameMeta
mkBaseListMeta "reverse", PatternType
forall a. PatternBool a => a
(?))

-- | 'Inspection' for 'stan0102' — infinite 'Data.OldList.isSuffixOf' @STAN-0102@.
stan0102 :: Inspection
stan0102 :: Inspection
stan0102 = Id Inspection -> NonEmpty (NameMeta, PatternType) -> Inspection
mkInfiniteInspection (Text -> Id Inspection
forall a. Text -> Id a
Id "STAN-0102") (NonEmpty (NameMeta, PatternType) -> Inspection)
-> NonEmpty (NameMeta, PatternType) -> Inspection
forall a b. (a -> b) -> a -> b
$ OneItem (NonEmpty (NameMeta, PatternType))
-> NonEmpty (NameMeta, PatternType)
forall x. One x => OneItem x -> x
one (Text -> NameMeta
mkBaseOldListMeta "isSuffixOf", PatternType
forall a. PatternBool a => a
(?))

-- | 'Inspection' for 'stan0103' — infinite 'Data.Foldable.length' | 'Data.OldList.length' @STAN-0103@.
stan0103 :: Inspection
stan0103 :: Inspection
stan0103 = Id Inspection -> NonEmpty (NameMeta, PatternType) -> Inspection
mkInfiniteInspection (Text -> Id Inspection
forall a. Text -> Id a
Id "STAN-0103") (NonEmpty (NameMeta, PatternType) -> Inspection)
-> NonEmpty (NameMeta, PatternType) -> Inspection
forall a b. (a -> b) -> a -> b
$
        (Text -> NameMeta
mkBaseFoldableMeta "length", PatternType
listFunPattern)
    (NameMeta, PatternType)
-> [(NameMeta, PatternType)] -> NonEmpty (NameMeta, PatternType)
forall a. a -> [a] -> NonEmpty a
:| [(Text -> NameMeta
mkBaseListMeta     "length", PatternType
listFunPattern)]

-- | 'Inspection' for 'stan0104' — infinite 'Data.OldList.genericLength' @STAN-0104@.
stan0104 :: Inspection
stan0104 :: Inspection
stan0104 = Id Inspection -> NonEmpty (NameMeta, PatternType) -> Inspection
mkInfiniteInspection (Text -> Id Inspection
forall a. Text -> Id a
Id "STAN-0104") (NonEmpty (NameMeta, PatternType) -> Inspection)
-> NonEmpty (NameMeta, PatternType) -> Inspection
forall a b. (a -> b) -> a -> b
$ OneItem (NonEmpty (NameMeta, PatternType))
-> NonEmpty (NameMeta, PatternType)
forall x. One x => OneItem x -> x
one (Text -> NameMeta
mkBaseOldListMeta "genericLength", PatternType
forall a. PatternBool a => a
(?))

-- | 'Inspection' for 'stan0105' — infinite 'Data.Foldable.sum' @STAN-0105@.
stan0105 :: Inspection
stan0105 :: Inspection
stan0105 = Id Inspection -> NonEmpty (NameMeta, PatternType) -> Inspection
mkInfiniteInspection (Text -> Id Inspection
forall a. Text -> Id a
Id "STAN-0105") (NonEmpty (NameMeta, PatternType) -> Inspection)
-> NonEmpty (NameMeta, PatternType) -> Inspection
forall a b. (a -> b) -> a -> b
$ OneItem (NonEmpty (NameMeta, PatternType))
-> NonEmpty (NameMeta, PatternType)
forall x. One x => OneItem x -> x
one (Text -> NameMeta
mkBaseFoldableMeta "sum", PatternType
listFunPattern)

-- | 'Inspection' for 'stan0106' — infinite 'Data.Foldable.product' @STAN-0106@.
stan0106 :: Inspection
stan0106 :: Inspection
stan0106 = Id Inspection -> NonEmpty (NameMeta, PatternType) -> Inspection
mkInfiniteInspection (Text -> Id Inspection
forall a. Text -> Id a
Id "STAN-0106") (NonEmpty (NameMeta, PatternType) -> Inspection)
-> NonEmpty (NameMeta, PatternType) -> Inspection
forall a b. (a -> b) -> a -> b
$ OneItem (NonEmpty (NameMeta, PatternType))
-> NonEmpty (NameMeta, PatternType)
forall x. One x => OneItem x -> x
one (Text -> NameMeta
mkBaseFoldableMeta "product", PatternType
listFunPattern)