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

Static analysis of all HIE files.
-}

module Stan.Analysis
    ( Analysis (..)
    , runAnalysis
    ) where

import Data.Aeson.Micro (ToJSON (..), object, (.=))
import Extensions (ExtensionsError (..), OnOffExtension, ParsedExtensions (..),
                   SafeHaskellExtension, parseSourceWithPath, showOnOffExtension)
import Relude.Extra.Lens (Lens', lens, over)

import Stan.Analysis.Analyser (analyseAst)
import Stan.Cabal (mergeParsedExtensions)
import Stan.Core.Id (Id)
import Stan.Core.ModuleName (fromGhcModule)
import Stan.FileInfo (FileInfo (..), FileMap)
import Stan.Hie (countLinesOfCode)
import Stan.Hie.Compat (HieFile (..))
import Stan.Inspection (Inspection)
import Stan.Inspection.All (lookupInspectionById)
import Stan.Observation (Observation (..), Observations)

import qualified Data.HashMap.Strict as HM
import qualified Data.Map.Strict as Map
import qualified Data.Set as Set
import qualified Slist as S


{- | This data type stores all information collected during static analysis.
-}
data Analysis = Analysis
    { Analysis -> Int
analysisModulesNum          :: !Int
    , Analysis -> Int
analysisLinesOfCode         :: !Int
    , Analysis -> (Set OnOffExtension, Set SafeHaskellExtension)
analysisUsedExtensions      :: !(Set OnOffExtension, Set SafeHaskellExtension)
    , Analysis -> HashSet (Id Inspection)
analysisInspections         :: !(HashSet (Id Inspection))
    , Analysis -> Observations
analysisObservations        :: !Observations
    , Analysis -> Observations
analysisIgnoredObservations :: !Observations
    , Analysis -> FileMap
analysisFileMap             :: !FileMap
    } deriving stock (Int -> Analysis -> ShowS
[Analysis] -> ShowS
Analysis -> FilePath
(Int -> Analysis -> ShowS)
-> (Analysis -> FilePath) -> ([Analysis] -> ShowS) -> Show Analysis
forall a.
(Int -> a -> ShowS) -> (a -> FilePath) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Analysis -> ShowS
showsPrec :: Int -> Analysis -> ShowS
$cshow :: Analysis -> FilePath
show :: Analysis -> FilePath
$cshowList :: [Analysis] -> ShowS
showList :: [Analysis] -> ShowS
Show)

instance ToJSON Analysis where
    toJSON :: Analysis -> Value
toJSON Analysis{Int
(Set OnOffExtension, Set SafeHaskellExtension)
FileMap
HashSet (Id Inspection)
Observations
analysisModulesNum :: Analysis -> Int
analysisLinesOfCode :: Analysis -> Int
analysisUsedExtensions :: Analysis -> (Set OnOffExtension, Set SafeHaskellExtension)
analysisInspections :: Analysis -> HashSet (Id Inspection)
analysisObservations :: Analysis -> Observations
analysisIgnoredObservations :: Analysis -> Observations
analysisFileMap :: Analysis -> FileMap
analysisModulesNum :: Int
analysisLinesOfCode :: Int
analysisUsedExtensions :: (Set OnOffExtension, Set SafeHaskellExtension)
analysisInspections :: HashSet (Id Inspection)
analysisObservations :: Observations
analysisIgnoredObservations :: Observations
analysisFileMap :: FileMap
..} = [Pair] -> Value
object
        [ Text
"modulesNum"  Text -> Int -> Pair
forall v. ToJSON v => Text -> v -> Pair
.= Int
analysisModulesNum
        , Text
"linesOfCode" Text -> Int -> Pair
forall v. ToJSON v => Text -> v -> Pair
.= Int
analysisLinesOfCode
        , Text
"usedExtensions" Text -> [Text] -> Pair
forall v. ToJSON v => Text -> v -> Pair
.=
            let (Set OnOffExtension
ext, Set SafeHaskellExtension
safeExt) = (Set OnOffExtension, Set SafeHaskellExtension)
analysisUsedExtensions
            in (OnOffExtension -> Text) -> [OnOffExtension] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
map OnOffExtension -> Text
showOnOffExtension (Set OnOffExtension -> [OnOffExtension]
forall a. Set a -> [a]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList Set OnOffExtension
ext)
            [Text] -> [Text] -> [Text]
forall a. Semigroup a => a -> a -> a
<> (SafeHaskellExtension -> Text) -> [SafeHaskellExtension] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
map (forall b a. (Show a, IsString b) => a -> b
show @Text) (Set SafeHaskellExtension -> [SafeHaskellExtension]
forall a. Set a -> [a]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList Set SafeHaskellExtension
safeExt)
        , Text
"inspections"  Text -> [Id Inspection] -> Pair
forall v. ToJSON v => Text -> v -> Pair
.= HashSet (Id Inspection) -> [Id Inspection]
forall a. HashSet a -> [a]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList HashSet (Id Inspection)
analysisInspections
        , Text
"observations" Text -> [Observation] -> Pair
forall v. ToJSON v => Text -> v -> Pair
.= Observations -> [Observation]
toJsonObs Observations
analysisObservations
        , Text
"ignoredObservations" Text -> [Observation] -> Pair
forall v. ToJSON v => Text -> v -> Pair
.= Observations -> [Observation]
toJsonObs Observations
analysisIgnoredObservations
        , Text
"fileMap" Text -> [(Text, FileInfo)] -> Pair
forall v. ToJSON v => Text -> v -> Pair
.= ((FilePath, FileInfo) -> (Text, FileInfo))
-> [(FilePath, FileInfo)] -> [(Text, FileInfo)]
forall a b. (a -> b) -> [a] -> [b]
map ((FilePath -> Text) -> (FilePath, FileInfo) -> (Text, FileInfo)
forall a b c. (a -> b) -> (a, c) -> (b, c)
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first FilePath -> Text
forall a. ToText a => a -> Text
toText) (FileMap -> [(FilePath, FileInfo)]
forall k a. Map k a -> [(k, a)]
Map.toList FileMap
analysisFileMap)
        ]
      where
        toJsonObs :: Observations -> [Observation]
        toJsonObs :: Observations -> [Observation]
toJsonObs = Observations -> [Observation]
forall a. Slist a -> [a]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList (Observations -> [Observation])
-> (Observations -> Observations) -> Observations -> [Observation]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Observation -> RealSrcSpan) -> Observations -> Observations
forall b a. Ord b => (a -> b) -> Slist a -> Slist a
S.sortOn Observation -> RealSrcSpan
observationSrcSpan

modulesNumL :: Lens' Analysis Int
modulesNumL :: Lens' Analysis Int
modulesNumL = (Analysis -> Int)
-> (Analysis -> Int -> Analysis) -> Lens' Analysis Int
forall s a. (s -> a) -> (s -> a -> s) -> Lens' s a
lens
    Analysis -> Int
analysisModulesNum
    (\Analysis
analysis Int
new -> Analysis
analysis { analysisModulesNum = new })

linesOfCodeL :: Lens' Analysis Int
linesOfCodeL :: Lens' Analysis Int
linesOfCodeL = (Analysis -> Int)
-> (Analysis -> Int -> Analysis) -> Lens' Analysis Int
forall s a. (s -> a) -> (s -> a -> s) -> Lens' s a
lens
    Analysis -> Int
analysisLinesOfCode
    (\Analysis
analysis Int
new -> Analysis
analysis { analysisLinesOfCode = new })

extensionsL :: Lens' Analysis (Set OnOffExtension, Set SafeHaskellExtension)
extensionsL :: Lens' Analysis (Set OnOffExtension, Set SafeHaskellExtension)
extensionsL = (Analysis -> (Set OnOffExtension, Set SafeHaskellExtension))
-> (Analysis
    -> (Set OnOffExtension, Set SafeHaskellExtension) -> Analysis)
-> Lens' Analysis (Set OnOffExtension, Set SafeHaskellExtension)
forall s a. (s -> a) -> (s -> a -> s) -> Lens' s a
lens
    Analysis -> (Set OnOffExtension, Set SafeHaskellExtension)
analysisUsedExtensions
    (\Analysis
analysis (Set OnOffExtension, Set SafeHaskellExtension)
new -> Analysis
analysis { analysisUsedExtensions = new })

inspectionsL :: Lens' Analysis (HashSet (Id Inspection))
inspectionsL :: Lens' Analysis (HashSet (Id Inspection))
inspectionsL = (Analysis -> HashSet (Id Inspection))
-> (Analysis -> HashSet (Id Inspection) -> Analysis)
-> Lens' Analysis (HashSet (Id Inspection))
forall s a. (s -> a) -> (s -> a -> s) -> Lens' s a
lens
    Analysis -> HashSet (Id Inspection)
analysisInspections
    (\Analysis
analysis HashSet (Id Inspection)
new -> Analysis
analysis { analysisInspections = new })

observationsL :: Lens' Analysis Observations
observationsL :: Lens' Analysis Observations
observationsL = (Analysis -> Observations)
-> (Analysis -> Observations -> Analysis)
-> Lens' Analysis Observations
forall s a. (s -> a) -> (s -> a -> s) -> Lens' s a
lens
    Analysis -> Observations
analysisObservations
    (\Analysis
analysis Observations
new -> Analysis
analysis { analysisObservations = new })

ignoredObservationsL :: Lens' Analysis Observations
ignoredObservationsL :: Lens' Analysis Observations
ignoredObservationsL = (Analysis -> Observations)
-> (Analysis -> Observations -> Analysis)
-> Lens' Analysis Observations
forall s a. (s -> a) -> (s -> a -> s) -> Lens' s a
lens
    Analysis -> Observations
analysisIgnoredObservations
    (\Analysis
analysis Observations
new -> Analysis
analysis { analysisIgnoredObservations = new })

fileMapL :: Lens' Analysis FileMap
fileMapL :: Lens' Analysis FileMap
fileMapL = (Analysis -> FileMap)
-> (Analysis -> FileMap -> Analysis) -> Lens' Analysis FileMap
forall s a. (s -> a) -> (s -> a -> s) -> Lens' s a
lens
    Analysis -> FileMap
analysisFileMap
    (\Analysis
analysis FileMap
new -> Analysis
analysis { analysisFileMap = new })

initialAnalysis :: Analysis
initialAnalysis :: Analysis
initialAnalysis = Analysis
    { analysisModulesNum :: Int
analysisModulesNum          = Int
0
    , analysisLinesOfCode :: Int
analysisLinesOfCode         = Int
0
    , analysisUsedExtensions :: (Set OnOffExtension, Set SafeHaskellExtension)
analysisUsedExtensions      = (Set OnOffExtension, Set SafeHaskellExtension)
forall a. Monoid a => a
mempty
    , analysisInspections :: HashSet (Id Inspection)
analysisInspections         = HashSet (Id Inspection)
forall a. Monoid a => a
mempty
    , analysisObservations :: Observations
analysisObservations        = Observations
forall a. Monoid a => a
mempty
    , analysisIgnoredObservations :: Observations
analysisIgnoredObservations = Observations
forall a. Monoid a => a
mempty
    , analysisFileMap :: FileMap
analysisFileMap             = FileMap
forall a. Monoid a => a
mempty
    }

incModulesNum :: State Analysis ()
incModulesNum :: State Analysis ()
incModulesNum = (Analysis -> Analysis) -> State Analysis ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify' ((Analysis -> Analysis) -> State Analysis ())
-> (Analysis -> Analysis) -> State Analysis ()
forall a b. (a -> b) -> a -> b
$ Lens' Analysis Int -> (Int -> Int) -> Analysis -> Analysis
forall s a. Lens' s a -> (a -> a) -> s -> s
over (Int -> f Int) -> Analysis -> f Analysis
Lens' Analysis Int
modulesNumL (Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1)

{- | Increase the total loc ('analysisLinesOfCode') by the given number of
analised lines of code.
-}
incLinesOfCode :: Int -> State Analysis ()
incLinesOfCode :: Int -> State Analysis ()
incLinesOfCode Int
num = (Analysis -> Analysis) -> State Analysis ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify' ((Analysis -> Analysis) -> State Analysis ())
-> (Analysis -> Analysis) -> State Analysis ()
forall a b. (a -> b) -> a -> b
$ Lens' Analysis Int -> (Int -> Int) -> Analysis -> Analysis
forall s a. Lens' s a -> (a -> a) -> s -> s
over (Int -> f Int) -> Analysis -> f Analysis
Lens' Analysis Int
linesOfCodeL (Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
num)

-- | Add set of 'Inspection' 'Id's to the existing set.
addInspections :: HashSet (Id Inspection) -> State Analysis ()
addInspections :: HashSet (Id Inspection) -> State Analysis ()
addInspections HashSet (Id Inspection)
ins = (Analysis -> Analysis) -> State Analysis ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify' ((Analysis -> Analysis) -> State Analysis ())
-> (Analysis -> Analysis) -> State Analysis ()
forall a b. (a -> b) -> a -> b
$ Lens' Analysis (HashSet (Id Inspection))
-> (HashSet (Id Inspection) -> HashSet (Id Inspection))
-> Analysis
-> Analysis
forall s a. Lens' s a -> (a -> a) -> s -> s
over (HashSet (Id Inspection) -> f (HashSet (Id Inspection)))
-> Analysis -> f Analysis
Lens' Analysis (HashSet (Id Inspection))
inspectionsL (HashSet (Id Inspection)
ins HashSet (Id Inspection)
-> HashSet (Id Inspection) -> HashSet (Id Inspection)
forall a. Semigroup a => a -> a -> a
<>)

-- | Add list of 'Observation's to the beginning of the existing list
addObservations :: Observations -> State Analysis ()
addObservations :: Observations -> State Analysis ()
addObservations Observations
observations = (Analysis -> Analysis) -> State Analysis ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify' ((Analysis -> Analysis) -> State Analysis ())
-> (Analysis -> Analysis) -> State Analysis ()
forall a b. (a -> b) -> a -> b
$ Lens' Analysis Observations
-> (Observations -> Observations) -> Analysis -> Analysis
forall s a. Lens' s a -> (a -> a) -> s -> s
over (Observations -> f Observations) -> Analysis -> f Analysis
Lens' Analysis Observations
observationsL (Observations
observations Observations -> Observations -> Observations
forall a. Semigroup a => a -> a -> a
<>)

-- | Add list of 'Observation's to the beginning of the existing list
addIgnoredObservations :: Observations -> State Analysis ()
addIgnoredObservations :: Observations -> State Analysis ()
addIgnoredObservations Observations
obs = (Analysis -> Analysis) -> State Analysis ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify' ((Analysis -> Analysis) -> State Analysis ())
-> (Analysis -> Analysis) -> State Analysis ()
forall a b. (a -> b) -> a -> b
$ Lens' Analysis Observations
-> (Observations -> Observations) -> Analysis -> Analysis
forall s a. Lens' s a -> (a -> a) -> s -> s
over (Observations -> f Observations) -> Analysis -> f Analysis
Lens' Analysis Observations
ignoredObservationsL (Observations
obs Observations -> Observations -> Observations
forall a. Semigroup a => a -> a -> a
<>)

-- | Collect all unique used extensions.
addExtensions :: ParsedExtensions -> State Analysis ()
addExtensions :: ParsedExtensions -> State Analysis ()
addExtensions ParsedExtensions{[OnOffExtension]
Maybe SafeHaskellExtension
parsedExtensionsAll :: [OnOffExtension]
parsedExtensionsSafe :: Maybe SafeHaskellExtension
parsedExtensionsAll :: ParsedExtensions -> [OnOffExtension]
parsedExtensionsSafe :: ParsedExtensions -> Maybe SafeHaskellExtension
..} = (Analysis -> Analysis) -> State Analysis ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify' ((Analysis -> Analysis) -> State Analysis ())
-> (Analysis -> Analysis) -> State Analysis ()
forall a b. (a -> b) -> a -> b
$ Lens' Analysis (Set OnOffExtension, Set SafeHaskellExtension)
-> ((Set OnOffExtension, Set SafeHaskellExtension)
    -> (Set OnOffExtension, Set SafeHaskellExtension))
-> Analysis
-> Analysis
forall s a. Lens' s a -> (a -> a) -> s -> s
over ((Set OnOffExtension, Set SafeHaskellExtension)
 -> f (Set OnOffExtension, Set SafeHaskellExtension))
-> Analysis -> f Analysis
Lens' Analysis (Set OnOffExtension, Set SafeHaskellExtension)
extensionsL
    (\(Set OnOffExtension
setExts, Set SafeHaskellExtension
setSafeExts) ->
        ( Set OnOffExtension -> Set OnOffExtension -> Set OnOffExtension
forall a. Ord a => Set a -> Set a -> Set a
Set.union ([OnOffExtension] -> Set OnOffExtension
forall a. Ord a => [a] -> Set a
Set.fromList [OnOffExtension]
parsedExtensionsAll) Set OnOffExtension
setExts
        , Set SafeHaskellExtension
-> (SafeHaskellExtension -> Set SafeHaskellExtension)
-> Maybe SafeHaskellExtension
-> Set SafeHaskellExtension
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Set SafeHaskellExtension
setSafeExts (SafeHaskellExtension
-> Set SafeHaskellExtension -> Set SafeHaskellExtension
forall a. Ord a => a -> Set a -> Set a
`Set.insert` Set SafeHaskellExtension
setSafeExts) Maybe SafeHaskellExtension
parsedExtensionsSafe
        )
    )

-- | Update 'FileInfo' for the given 'FilePath'.
updateFileMap :: FilePath -> FileInfo -> State Analysis ()
updateFileMap :: FilePath -> FileInfo -> State Analysis ()
updateFileMap FilePath
fp FileInfo
fi = (Analysis -> Analysis) -> State Analysis ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify' ((Analysis -> Analysis) -> State Analysis ())
-> (Analysis -> Analysis) -> State Analysis ()
forall a b. (a -> b) -> a -> b
$ Lens' Analysis FileMap
-> (FileMap -> FileMap) -> Analysis -> Analysis
forall s a. Lens' s a -> (a -> a) -> s -> s
over (FileMap -> f FileMap) -> Analysis -> f Analysis
Lens' Analysis FileMap
fileMapL (FilePath -> FileInfo -> FileMap -> FileMap
forall k a. Ord k => k -> a -> Map k a -> Map k a
Map.insert FilePath
fp FileInfo
fi)

{- | Perform static analysis of given 'HieFile'.
-}
runAnalysis
    :: Map FilePath (Either ExtensionsError ParsedExtensions)
    -> HashMap FilePath (HashSet (Id Inspection))
    -> [Id Observation]  -- ^ List of to-be-ignored Observations.
    -> [HieFile]
    -> Analysis
runAnalysis :: Map FilePath (Either ExtensionsError ParsedExtensions)
-> HashMap FilePath (HashSet (Id Inspection))
-> [Id Observation]
-> [HieFile]
-> Analysis
runAnalysis Map FilePath (Either ExtensionsError ParsedExtensions)
cabalExtensionsMap HashMap FilePath (HashSet (Id Inspection))
checksMap [Id Observation]
obs = Analysis -> State Analysis () -> Analysis
forall s a. s -> State s a -> s
executingState Analysis
initialAnalysis (State Analysis () -> Analysis)
-> ([HieFile] -> State Analysis ()) -> [HieFile] -> Analysis
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
    Map FilePath (Either ExtensionsError ParsedExtensions)
-> HashMap FilePath (HashSet (Id Inspection))
-> [Id Observation]
-> [HieFile]
-> State Analysis ()
analyse Map FilePath (Either ExtensionsError ParsedExtensions)
cabalExtensionsMap HashMap FilePath (HashSet (Id Inspection))
checksMap [Id Observation]
obs

analyse
    :: Map FilePath (Either ExtensionsError ParsedExtensions)
    -> HashMap FilePath (HashSet (Id Inspection))
    -> [Id Observation]  -- ^ List of to-be-ignored Observations.
    -> [HieFile]
    -> State Analysis ()
analyse :: Map FilePath (Either ExtensionsError ParsedExtensions)
-> HashMap FilePath (HashSet (Id Inspection))
-> [Id Observation]
-> [HieFile]
-> State Analysis ()
analyse Map FilePath (Either ExtensionsError ParsedExtensions)
_extsMap HashMap FilePath (HashSet (Id Inspection))
_checksMap [Id Observation]
_observations [] = State Analysis ()
forall (f :: * -> *). Applicative f => f ()
pass
analyse Map FilePath (Either ExtensionsError ParsedExtensions)
cabalExtensions HashMap FilePath (HashSet (Id Inspection))
checksMap [Id Observation]
observations (hieFile :: HieFile
hieFile@HieFile{FilePath
[AvailInfo]
ByteString
Array Int HieTypeFlat
Module
HieASTs Int
hie_hs_file :: FilePath
hie_module :: Module
hie_types :: Array Int HieTypeFlat
hie_asts :: HieASTs Int
hie_exports :: [AvailInfo]
hie_hs_src :: ByteString
hie_hs_file :: HieFile -> FilePath
hie_module :: HieFile -> Module
hie_types :: HieFile -> Array Int HieTypeFlat
hie_asts :: HieFile -> HieASTs Int
hie_exports :: HieFile -> [AvailInfo]
hie_hs_src :: HieFile -> ByteString
..}:[HieFile]
hieFiles) = do
    Maybe (HashSet (Id Inspection))
-> (HashSet (Id Inspection) -> State Analysis ())
-> State Analysis ()
forall (f :: * -> *) a.
Applicative f =>
Maybe a -> (a -> f ()) -> f ()
whenJust (FilePath
-> HashMap FilePath (HashSet (Id Inspection))
-> Maybe (HashSet (Id Inspection))
forall k v. (Eq k, Hashable k) => k -> HashMap k v -> Maybe v
HM.lookup FilePath
hie_hs_file HashMap FilePath (HashSet (Id Inspection))
checksMap)
        (HieFile
-> Map FilePath (Either ExtensionsError ParsedExtensions)
-> [Id Observation]
-> HashSet (Id Inspection)
-> State Analysis ()
analyseHieFile HieFile
hieFile Map FilePath (Either ExtensionsError ParsedExtensions)
cabalExtensions [Id Observation]
observations)
    Map FilePath (Either ExtensionsError ParsedExtensions)
-> HashMap FilePath (HashSet (Id Inspection))
-> [Id Observation]
-> [HieFile]
-> State Analysis ()
analyse Map FilePath (Either ExtensionsError ParsedExtensions)
cabalExtensions HashMap FilePath (HashSet (Id Inspection))
checksMap [Id Observation]
observations [HieFile]
hieFiles

analyseHieFile
    :: HieFile
    -> Map FilePath (Either ExtensionsError ParsedExtensions)
    -> [Id Observation]  -- ^ List of to-be-ignored Observations.
    -> HashSet (Id Inspection)
    -> State Analysis ()
analyseHieFile :: HieFile
-> Map FilePath (Either ExtensionsError ParsedExtensions)
-> [Id Observation]
-> HashSet (Id Inspection)
-> State Analysis ()
analyseHieFile hieFile :: HieFile
hieFile@HieFile{FilePath
[AvailInfo]
ByteString
Array Int HieTypeFlat
Module
HieASTs Int
hie_hs_file :: HieFile -> FilePath
hie_module :: HieFile -> Module
hie_types :: HieFile -> Array Int HieTypeFlat
hie_asts :: HieFile -> HieASTs Int
hie_exports :: HieFile -> [AvailInfo]
hie_hs_src :: HieFile -> ByteString
hie_hs_file :: FilePath
hie_module :: Module
hie_types :: Array Int HieTypeFlat
hie_asts :: HieASTs Int
hie_exports :: [AvailInfo]
hie_hs_src :: ByteString
..} Map FilePath (Either ExtensionsError ParsedExtensions)
cabalExts [Id Observation]
obs HashSet (Id Inspection)
insIds = do
    -- traceM (hie_hs_file hieFile)
    let fileInfoLoc :: Int
fileInfoLoc = HieFile -> Int
countLinesOfCode HieFile
hieFile
    let fileInfoCabalExtensions :: Either ExtensionsError ParsedExtensions
fileInfoCabalExtensions = Either ExtensionsError ParsedExtensions
-> Maybe (Either ExtensionsError ParsedExtensions)
-> Either ExtensionsError ParsedExtensions
forall a. a -> Maybe a -> a
fromMaybe
            (ExtensionsError -> Either ExtensionsError ParsedExtensions
forall a b. a -> Either a b
Left (ExtensionsError -> Either ExtensionsError ParsedExtensions)
-> ExtensionsError -> Either ExtensionsError ParsedExtensions
forall a b. (a -> b) -> a -> b
$ FilePath -> ExtensionsError
NotCabalModule FilePath
hie_hs_file)
            (FilePath
-> Map FilePath (Either ExtensionsError ParsedExtensions)
-> Maybe (Either ExtensionsError ParsedExtensions)
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup FilePath
hie_hs_file Map FilePath (Either ExtensionsError ParsedExtensions)
cabalExts)
    let fileInfoExtensions :: Either ExtensionsError ParsedExtensions
fileInfoExtensions = (ModuleParseError -> ExtensionsError)
-> Either ModuleParseError ParsedExtensions
-> Either ExtensionsError ParsedExtensions
forall a b c. (a -> b) -> Either a c -> Either b c
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first (FilePath -> ModuleParseError -> ExtensionsError
ModuleParseError FilePath
hie_hs_file) (Either ModuleParseError ParsedExtensions
 -> Either ExtensionsError ParsedExtensions)
-> Either ModuleParseError ParsedExtensions
-> Either ExtensionsError ParsedExtensions
forall a b. (a -> b) -> a -> b
$
            FilePath -> ByteString -> Either ModuleParseError ParsedExtensions
parseSourceWithPath FilePath
hie_hs_file ByteString
hie_hs_src
    let fileInfoPath :: FilePath
fileInfoPath = FilePath
hie_hs_file
    let fileInfoModuleName :: ModuleName
fileInfoModuleName = Module -> ModuleName
fromGhcModule Module
hie_module
    -- merge cabal and module extensions and update overall exts
    let fileInfoMergedExtensions :: ExtensionsResult
fileInfoMergedExtensions = Either ExtensionsError ParsedExtensions
-> Either ExtensionsError ParsedExtensions -> ExtensionsResult
mergeParsedExtensions Either ExtensionsError ParsedExtensions
fileInfoCabalExtensions Either ExtensionsError ParsedExtensions
fileInfoExtensions
    -- get list of inspections for the file
    let inss :: [Inspection]
inss = (Id Inspection -> Maybe Inspection)
-> [Id Inspection] -> [Inspection]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe Id Inspection -> Maybe Inspection
lookupInspectionById (HashSet (Id Inspection) -> [Id Inspection]
forall a. HashSet a -> [a]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList HashSet (Id Inspection)
insIds)
    -- get all observations by analysing ast
    let allObservations :: Observations
allObservations = HieFile -> ExtensionsResult -> [Inspection] -> Observations
analyseAst HieFile
hieFile ExtensionsResult
fileInfoMergedExtensions [Inspection]
inss
    let (Observations
ignoredObs, Observations
fileInfoObservations) = (Observation -> Bool)
-> Observations -> (Observations, Observations)
forall a. (a -> Bool) -> Slist a -> (Slist a, Slist a)
S.partition ((Id Observation -> [Id Observation] -> Bool
forall (f :: * -> *) a.
(Foldable f, DisallowElem f, Eq a) =>
a -> f a -> Bool
`elem` [Id Observation]
obs) (Id Observation -> Bool)
-> (Observation -> Id Observation) -> Observation -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Observation -> Id Observation
observationId) Observations
allObservations

    State Analysis ()
incModulesNum
    Int -> State Analysis ()
incLinesOfCode Int
fileInfoLoc
    FilePath -> FileInfo -> State Analysis ()
updateFileMap FilePath
hie_hs_file FileInfo{Int
FilePath
Either ExtensionsError ParsedExtensions
ExtensionsResult
Observations
ModuleName
fileInfoLoc :: Int
fileInfoCabalExtensions :: Either ExtensionsError ParsedExtensions
fileInfoExtensions :: Either ExtensionsError ParsedExtensions
fileInfoPath :: FilePath
fileInfoModuleName :: ModuleName
fileInfoMergedExtensions :: ExtensionsResult
fileInfoObservations :: Observations
fileInfoPath :: FilePath
fileInfoModuleName :: ModuleName
fileInfoLoc :: Int
fileInfoCabalExtensions :: Either ExtensionsError ParsedExtensions
fileInfoExtensions :: Either ExtensionsError ParsedExtensions
fileInfoMergedExtensions :: ExtensionsResult
fileInfoObservations :: Observations
..}
    Either ExtensionsError ParsedExtensions
-> (ParsedExtensions -> State Analysis ()) -> State Analysis ()
forall (f :: * -> *) l r.
Applicative f =>
Either l r -> (r -> f ()) -> f ()
whenRight_ Either ExtensionsError ParsedExtensions
fileInfoExtensions ParsedExtensions -> State Analysis ()
addExtensions
    Either ExtensionsError ParsedExtensions
-> (ParsedExtensions -> State Analysis ()) -> State Analysis ()
forall (f :: * -> *) l r.
Applicative f =>
Either l r -> (r -> f ()) -> f ()
whenRight_ Either ExtensionsError ParsedExtensions
fileInfoCabalExtensions ParsedExtensions -> State Analysis ()
addExtensions
    HashSet (Id Inspection) -> State Analysis ()
addInspections HashSet (Id Inspection)
insIds
    Observations -> State Analysis ()
addObservations Observations
fileInfoObservations
    Observations -> State Analysis ()
addIgnoredObservations Observations
ignoredObs