stan-0.0.0.0: src/Stan/Inspection/Partial.hs
{- |
Copyright: (c) 2020 Kowainik
SPDX-License-Identifier: MPL-2.0
Maintainer: Kowainik <xrom.xkov@gmail.com>
Contains all 'Inspection's for partial functions.
The __partial__ inspections are in ranges:
* @STAN-0001 .. STAN-0100@
-}
module Stan.Inspection.Partial
( -- * Partial 'Inspection's
-- *** Partial 'GHC.List.head'
stan0001
-- *** Partial 'GHC.List.tail'
, stan0002
-- *** Partial 'GHC.List.init'
, stan0003
-- *** Partial 'GHC.List.last'
, stan0004
-- *** Partial 'GHC.List.!!'
, stan0005
-- *** Partial 'GHC.List.cycle'
, stan0006
-- *** Partial 'Data.OldList.genericIndex'
, stan0007
-- *** Partial 'Data.Maybe.fromJust'
, stan0008
-- *** Partial 'Text.Read.read'
, stan0009
-- *** Partial 'GHC.Enum.succ'
, stan0010
-- *** Partial 'GHC.Enum.pred'
, stan0011
-- *** Partial 'GHC.Enum.toEnum'
, stan0012
-- *** Partial 'Data.Foldable.maximum'
, stan0013
-- *** Partial 'Data.Foldable.minimum'
, stan0014
-- *** Partial 'Data.Foldable.maximumBy'
, stan0015
-- *** Partial 'Data.Foldable.minimumBy'
, stan0016
-- *** Partial 'Data.Foldable.foldl1'
, stan0017
-- *** Partial 'Data.Foldable.foldl1\''
, stan0018
-- *** Partial 'Data.Foldable.foldr1'
, stan0019
-- *** Partial instance for 'NonEmpty' method 'GHC.Exts.fromList'
, stan0020
-- *** Partial instance for 'Natural' method 'GHC.Num.fromInteger'
, stan0021
-- * List of all partial 'Inspection's
, partialInspectionsMap
) where
import Prelude hiding ((&&&))
import Relude.Extra.Lens ((%~), (.~))
import Relude.Extra.Tuple (fmapToFst)
import Stan.Core.Id (Id (..))
import Stan.Inspection (Inspection (..), InspectionAnalysis (..), InspectionsMap, analysisL,
categoryL, descriptionL, solutionL)
import Stan.NameMeta (NameMeta (..), baseNameFrom, mkBaseFoldableMeta, mkBaseListMeta,
mkBaseOldListMeta)
import Stan.Pattern.Ast (PatternAst (PatternAstName), namesToPatternAst)
import Stan.Pattern.Edsl (PatternBool (..))
import Stan.Pattern.Type (PatternType (..), integerPattern, listFunPattern, listPattern,
naturalPattern, nonEmptyPattern, (|->))
import Stan.Severity (Severity (..))
import qualified Stan.Category as Category
-- | All partial 'Inspection's.
partialInspectionsMap :: InspectionsMap
partialInspectionsMap = fromList $ fmapToFst inspectionId
[ stan0001
, stan0002
, stan0003
, stan0004
, stan0005
, stan0006
, stan0007
, stan0008
, stan0009
, stan0010
, stan0011
, stan0012
, stan0013
, stan0014
, stan0015
, stan0016
, stan0017
, stan0018
, stan0019
, stan0020
, stan0021
]
-- | Smart constructor to create generic partial 'Inspection' with a given 'Pattern'.
mkPartialInspectionPattern
:: Id Inspection
-> NameMeta
-> PatternType
-> Text -- ^ Type name
-> Inspection
mkPartialInspectionPattern insId nameMeta@NameMeta{..} pat typeName = Inspection
{ inspectionId = insId
, inspectionName = "Partial: " <> nameMetaPackage <> "/" <> nameMetaName
, inspectionDescription = usage nameMetaName typeName
, inspectionSolution = []
, inspectionCategory = one Category.partial
, inspectionSeverity = Warning
, inspectionAnalysis = FindAst $ PatternAstName nameMeta pat
}
-- | Smart constructor to create generic partial 'Inspection' with 'PatternAnything'.
mkPartialInspection
:: Id Inspection
-> NameMeta
-> Text -- ^ Type name
-> Inspection
mkPartialInspection insId nameMeta =
mkPartialInspectionPattern insId nameMeta (?)
usage :: Text -> Text -> Text
usage funName forWhat =
"Usage of partial function '" <> funName <> "' for " <> forWhat
{- | Smart constructor to create partial 'Inspection' for functions
that work with lists.
-}
mkPartialInspectionList :: Id Inspection -> NameMeta -> Inspection
mkPartialInspectionList insId nameMeta = mkPartialInspection insId nameMeta "lists"
& categoryL %~ (<> one Category.list)
& solutionL .~
[ "Replace list with 'NonEmpty' from 'Data.List.NonEmpty'"
, "Use explicit pattern-matching over lists"
]
{- | Smart constructor to create partial 'Inspection' for functions
that work with enumerable types.
-}
mkPartialInspectionEnum :: Id Inspection -> Text -> PatternType -> [Text] -> Inspection
mkPartialInspectionEnum insId funName pat solution =
mkPartialInspectionPattern insId enumMeta pat ""
& descriptionL .~ usage funName "enumerable types"
& solutionL .~ solution
where
enumMeta :: NameMeta
enumMeta = funName `baseNameFrom` "GHC.Enum"
-- | 'Inspection' — partial 'GHC.List.head' @STAN-0001@.
stan0001 :: Inspection
stan0001 = mkPartialInspectionList (Id "STAN-0001") (mkBaseListMeta "head")
-- | 'Inspection' — partial 'GHC.List.tail' @STAN-0002@.
stan0002 :: Inspection
stan0002 = mkPartialInspectionList (Id "STAN-0002") (mkBaseListMeta "tail")
-- | 'Inspection' — partial 'GHC.List.init' @STAN-0003@.
stan0003 :: Inspection
stan0003 = mkPartialInspectionList (Id "STAN-0003") (mkBaseListMeta "init")
-- | 'Inspection' — partial 'GHC.List.last' @STAN-0004@.
stan0004 :: Inspection
stan0004 = mkPartialInspectionList (Id "STAN-0004") (mkBaseListMeta "last")
-- | 'Inspection' — partial 'GHC.List.!!' @STAN-0005@.
stan0005 :: Inspection
stan0005 = mkPartialInspectionList (Id "STAN-0005") (mkBaseListMeta "!!")
& solutionL .~ []
-- | 'Inspection' — partial 'GHC.List.cycle' @STAN-0006@.
stan0006 :: Inspection
stan0006 = mkPartialInspectionList (Id "STAN-0006") (mkBaseListMeta "cycle")
-- | 'Inspection' — partial 'Data.OldList.genericIndex' @STAN-0007@.
stan0007 :: Inspection
stan0007 = mkPartialInspectionList (Id "STAN-0007") (mkBaseOldListMeta "genericIndex")
& solutionL .~ []
-- | 'Inspection' — partial 'Data.Maybe.fromJust' @STAN-0008@.
stan0008 :: Inspection
stan0008 = mkPartialInspection (Id "STAN-0008") fromJustNameMeta "'Maybe'"
& solutionL .~
[ "Use explicit pattern-matching over Maybe"
, "Use one of the standard functions: 'maybe', 'fromMaybe'"
]
where
fromJustNameMeta :: NameMeta
fromJustNameMeta = "fromJust" `baseNameFrom` "Data.Maybe"
-- | 'Inspection' — partial 'Text.Read.read' @STAN-0009@.
stan0009 :: Inspection
stan0009 = mkPartialInspection (Id "STAN-0009") readNameMeta ""
& descriptionL .~ usage "read" "parsing 'String'"
& solutionL .~
[ "Use 'readMaybe' or 'readEither' to handle failed parsing"
]
where
readNameMeta :: NameMeta
readNameMeta = "read" `baseNameFrom` "Text.Read"
-- | 'Inspection' — partial 'GHC.Enum.succ' @STAN-0010@.
stan0010 :: Inspection
stan0010 = mkPartialInspectionEnum
(Id "STAN-0010")
"succ"
(neg (integerPattern |-> (?)) &&& neg (naturalPattern |-> (?)))
[ "Use '(+ 1)' for integral types (but be aware of arithmetic overflow)"
, "{Extra dependency} Use 'next' from 'Relude.Extra.Enum' in 'relude'"
]
-- | 'Inspection' — partial 'GHC.Enum.pred' @STAN-0011@.
stan0011 :: Inspection
stan0011 = mkPartialInspectionEnum
(Id "STAN-0011")
"pred"
(neg (integerPattern |-> (?)))
[ "Use '(- 1)' for integral types (but be aware of arithmetic overflow)"
, "{Extra dependency} Use 'prev' from 'Relude.Extra.Enum' in 'relude'"
]
-- | 'Inspection' — partial 'GHC.Enum.toEnum' @STAN-0012@.
stan0012 :: Inspection
stan0012 = mkPartialInspectionEnum (Id "STAN-0012") "toEnum" (?)
[ "{Extra dependency} Use 'safeToEnum' from 'Relude.Extra.Enum' in 'relude'"
]
-- | 'Inspection' — partial 'Data.Foldable.maximum' @STAN-0013@.
stan0013 :: Inspection
stan0013 = mkPartialInspectionPattern
(Id "STAN-0013") (mkBaseFoldableMeta "maximum") listFunPattern ""
-- | 'Inspection' — partial 'Data.Foldable.minimum' @STAN-0014@.
stan0014 :: Inspection
stan0014 = mkPartialInspectionPattern
(Id "STAN-0014") (mkBaseFoldableMeta "minimum") listFunPattern ""
orderingFunPattern :: PatternType
orderingFunPattern = (?) |-> listFunPattern
-- | 'Inspection' — partial 'Data.Foldable.maximumBy' @STAN-0015@.
stan0015 :: Inspection
stan0015 = mkPartialInspectionPattern
(Id "STAN-0015") (mkBaseFoldableMeta "maximumBy") orderingFunPattern ""
-- | 'Inspection' — partial 'Data.Foldable.minimumBy' @STAN-0016@.
stan0016 :: Inspection
stan0016 = mkPartialInspectionPattern
(Id "STAN-0016") (mkBaseFoldableMeta "minimumBy") orderingFunPattern ""
-- | 'Inspection' — partial 'Data.Foldable.foldl1' @STAN-0017@.
stan0017 :: Inspection
stan0017 = mkPartialInspectionPattern
(Id "STAN-0017") (mkBaseFoldableMeta "foldl1") orderingFunPattern ""
-- | 'Inspection' — partial 'Data.Foldable.foldl1\'' @STAN-0018@.
stan0018 :: Inspection
stan0018 = mkPartialInspectionList (Id "STAN-0018") (mkBaseListMeta "foldl1'")
-- | 'Inspection' — partial 'Data.Foldable.foldr1' @STAN-0019@.
stan0019 :: Inspection
stan0019 = mkPartialInspectionPattern
(Id "STAN-0019") (mkBaseFoldableMeta "foldr1") orderingFunPattern ""
-- | 'Inspection' — partial 'GHC.Exts.fromList' @STAN-0020@.
stan0020 :: Inspection
stan0020 = mkPartialInspectionPattern (Id "STAN-0020") exts pat ""
& analysisL .~ FindAst (namesToPatternAst $ (exts, pat) :| [(ne, pat)])
where
pat = listPattern |-> nonEmptyPattern
exts = "fromList" `baseNameFrom` "GHC.Exts"
ne = "fromList" `baseNameFrom` "Data.List.NonEmpty"
-- | 'Inspection' — partial 'GHC.Num.fromInteger' @STAN-0021@.
stan0021 :: Inspection
stan0021 = mkPartialInspectionPattern
(Id "STAN-0021")
("fromInteger" `baseNameFrom` "GHC.Num")
(integerPattern |-> naturalPattern)
""