{- | Copyright: (c) 2020 Kowainik SPDX-License-Identifier: MPL-2.0 Maintainer: Kowainik 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) ""