{- |
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 (analysisByInspection)
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 -> String
(Int -> Analysis -> ShowS)
-> (Analysis -> String) -> ([Analysis] -> ShowS) -> Show Analysis
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Analysis] -> ShowS
$cshowList :: [Analysis] -> ShowS
show :: Analysis -> String
$cshow :: Analysis -> String
showsPrec :: Int -> Analysis -> ShowS
$cshowsPrec :: Int -> Analysis -> ShowS
Show)

instance ToJSON Analysis where
    toJSON :: Analysis -> Value
toJSON Analysis{..} = [Pair] -> Value
object
        [ "modulesNum"  Text -> Int -> Pair
forall v. ToJSON v => Text -> v -> Pair
.= Int
analysisModulesNum
        , "linesOfCode" Text -> Int -> Pair
forall v. ToJSON v => Text -> v -> Pair
.= Int
analysisLinesOfCode
        , "usedExtensions" Text -> [Text] -> Pair
forall v. ToJSON v => Text -> v -> Pair
.=
            let (ext :: Set OnOffExtension
ext, safeExt :: 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 (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 a. (Show a, IsString Text) => a -> Text
forall b a. (Show a, IsString b) => a -> b
show @Text) (Set SafeHaskellExtension -> [SafeHaskellExtension]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList Set SafeHaskellExtension
safeExt)
        , "inspections"  Text -> [Id Inspection] -> Pair
forall v. ToJSON v => Text -> v -> Pair
.= HashSet (Id Inspection) -> [Id Inspection]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList HashSet (Id Inspection)
analysisInspections
        , "observations" Text -> [Observation] -> Pair
forall v. ToJSON v => Text -> v -> Pair
.= Observations -> [Observation]
toJsonObs Observations
analysisObservations
        , "ignoredObservations" Text -> [Observation] -> Pair
forall v. ToJSON v => Text -> v -> Pair
.= Observations -> [Observation]
toJsonObs Observations
analysisIgnoredObservations
        , "fileMap" Text -> [(Text, FileInfo)] -> Pair
forall v. ToJSON v => Text -> v -> Pair
.= ((String, FileInfo) -> (Text, FileInfo))
-> [(String, FileInfo)] -> [(Text, FileInfo)]
forall a b. (a -> b) -> [a] -> [b]
map ((String -> Text) -> (String, FileInfo) -> (Text, FileInfo)
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first String -> Text
forall a. ToText a => a -> Text
toText) (FileMap -> [(String, FileInfo)]
forall k a. Map k a -> [(k, a)]
Map.toList FileMap
analysisFileMap)
        ]
      where
        toJsonObs :: Observations -> [Observation]
        toJsonObs :: Observations -> [Observation]
toJsonObs = Observations -> [Observation]
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 :: (Int -> f Int) -> Analysis -> f Analysis
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
analysis new :: Int
new -> Analysis
analysis { analysisModulesNum :: Int
analysisModulesNum = Int
new })

linesOfCodeL :: Lens' Analysis Int
linesOfCodeL :: (Int -> f Int) -> Analysis -> f Analysis
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
analysis new :: Int
new -> Analysis
analysis { analysisLinesOfCode :: Int
analysisLinesOfCode = Int
new })

extensionsL :: Lens' Analysis (Set OnOffExtension, Set SafeHaskellExtension)
extensionsL :: ((Set OnOffExtension, Set SafeHaskellExtension)
 -> f (Set OnOffExtension, Set SafeHaskellExtension))
-> Analysis -> f Analysis
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
analysis new :: (Set OnOffExtension, Set SafeHaskellExtension)
new -> Analysis
analysis { analysisUsedExtensions :: (Set OnOffExtension, Set SafeHaskellExtension)
analysisUsedExtensions = (Set OnOffExtension, Set SafeHaskellExtension)
new })

inspectionsL :: Lens' Analysis (HashSet (Id Inspection))
inspectionsL :: (HashSet (Id Inspection) -> f (HashSet (Id Inspection)))
-> Analysis -> f Analysis
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
analysis new :: HashSet (Id Inspection)
new -> Analysis
analysis { analysisInspections :: HashSet (Id Inspection)
analysisInspections = HashSet (Id Inspection)
new })

observationsL :: Lens' Analysis Observations
observationsL :: (Observations -> f Observations) -> Analysis -> f Analysis
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
analysis new :: Observations
new -> Analysis
analysis { analysisObservations :: Observations
analysisObservations = Observations
new })

ignoredObservationsL :: Lens' Analysis Observations
ignoredObservationsL :: (Observations -> f Observations) -> Analysis -> f Analysis
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
analysis new :: Observations
new -> Analysis
analysis { analysisIgnoredObservations :: Observations
analysisIgnoredObservations = Observations
new })

fileMapL :: Lens' Analysis FileMap
fileMapL :: (FileMap -> f FileMap) -> Analysis -> f Analysis
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
analysis new :: FileMap
new -> Analysis
analysis { analysisFileMap :: FileMap
analysisFileMap = FileMap
new })

initialAnalysis :: Analysis
initialAnalysis :: Analysis
initialAnalysis = $WAnalysis :: Int
-> Int
-> (Set OnOffExtension, Set SafeHaskellExtension)
-> HashSet (Id Inspection)
-> Observations
-> Observations
-> FileMap
-> Analysis
Analysis
    { analysisModulesNum :: Int
analysisModulesNum          = 0
    , analysisLinesOfCode :: Int
analysisLinesOfCode         = 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 Lens' Analysis Int
modulesNumL (Int -> Int -> Int
forall a. Num a => a -> a -> a
+ 1)

{- | Increase the total loc ('analysisLinesOfCode') by the given number of
analised lines of code.
-}
incLinesOfCode :: Int -> State Analysis ()
incLinesOfCode :: Int -> State Analysis ()
incLinesOfCode num :: 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 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 ins :: 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 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
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 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 obs :: 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 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{..} = (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 Lens' Analysis (Set OnOffExtension, Set SafeHaskellExtension)
extensionsL
    (\(setExts :: Set OnOffExtension
setExts, setSafeExts :: 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 :: String -> FileInfo -> State Analysis ()
updateFileMap fp :: String
fp fi :: 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 Lens' Analysis FileMap
fileMapL (String -> FileInfo -> FileMap -> FileMap
forall k a. Ord k => k -> a -> Map k a -> Map k a
Map.insert String
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 String (Either ExtensionsError ParsedExtensions)
-> HashMap String (HashSet (Id Inspection))
-> [Id Observation]
-> [HieFile]
-> Analysis
runAnalysis cabalExtensionsMap :: Map String (Either ExtensionsError ParsedExtensions)
cabalExtensionsMap checksMap :: HashMap String (HashSet (Id Inspection))
checksMap obs :: [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 String (Either ExtensionsError ParsedExtensions)
-> HashMap String (HashSet (Id Inspection))
-> [Id Observation]
-> [HieFile]
-> State Analysis ()
analyse Map String (Either ExtensionsError ParsedExtensions)
cabalExtensionsMap HashMap String (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 String (Either ExtensionsError ParsedExtensions)
-> HashMap String (HashSet (Id Inspection))
-> [Id Observation]
-> [HieFile]
-> State Analysis ()
analyse _extsMap :: Map String (Either ExtensionsError ParsedExtensions)
_extsMap _checksMap :: HashMap String (HashSet (Id Inspection))
_checksMap _observations :: [Id Observation]
_observations [] = State Analysis ()
forall (f :: * -> *). Applicative f => f ()
pass
analyse cabalExtensions :: Map String (Either ExtensionsError ParsedExtensions)
cabalExtensions checksMap :: HashMap String (HashSet (Id Inspection))
checksMap observations :: [Id Observation]
observations (hieFile :: HieFile
hieFile@HieFile{..}:hieFiles :: [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 (String
-> HashMap String (HashSet (Id Inspection))
-> Maybe (HashSet (Id Inspection))
forall k v. (Eq k, Hashable k) => k -> HashMap k v -> Maybe v
HM.lookup String
hie_hs_file HashMap String (HashSet (Id Inspection))
checksMap)
        (HieFile
-> Map String (Either ExtensionsError ParsedExtensions)
-> [Id Observation]
-> HashSet (Id Inspection)
-> State Analysis ()
analyseHieFile HieFile
hieFile Map String (Either ExtensionsError ParsedExtensions)
cabalExtensions [Id Observation]
observations)
    Map String (Either ExtensionsError ParsedExtensions)
-> HashMap String (HashSet (Id Inspection))
-> [Id Observation]
-> [HieFile]
-> State Analysis ()
analyse Map String (Either ExtensionsError ParsedExtensions)
cabalExtensions HashMap String (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 String (Either ExtensionsError ParsedExtensions)
-> [Id Observation]
-> HashSet (Id Inspection)
-> State Analysis ()
analyseHieFile hieFile :: HieFile
hieFile@HieFile{..} cabalExts :: Map String (Either ExtensionsError ParsedExtensions)
cabalExts obs :: [Id Observation]
obs insIds :: 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
$ String -> ExtensionsError
NotCabalModule String
hie_hs_file)
            (String
-> Map String (Either ExtensionsError ParsedExtensions)
-> Maybe (Either ExtensionsError ParsedExtensions)
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup String
hie_hs_file Map String (Either ExtensionsError ParsedExtensions)
cabalExts)
    let fileInfoExtensions :: Either ExtensionsError ParsedExtensions
fileInfoExtensions = (ModuleParseError -> ExtensionsError)
-> Either ModuleParseError ParsedExtensions
-> Either ExtensionsError ParsedExtensions
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first (String -> ModuleParseError -> ExtensionsError
ModuleParseError String
hie_hs_file) (Either ModuleParseError ParsedExtensions
 -> Either ExtensionsError ParsedExtensions)
-> Either ModuleParseError ParsedExtensions
-> Either ExtensionsError ParsedExtensions
forall a b. (a -> b) -> a -> b
$
            String -> ByteString -> Either ModuleParseError ParsedExtensions
parseSourceWithPath String
hie_hs_file ByteString
hie_hs_src
    let fileInfoPath :: String
fileInfoPath = String
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 ins :: [Inspection]
ins = (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 (t :: * -> *) a. Foldable t => t a -> [a]
toList HashSet (Id Inspection)
insIds)
    let allObservations :: Observations
allObservations = (Inspection -> Observations) -> [Inspection] -> Observations
forall (t :: * -> *) a b.
Foldable t =>
(a -> Slist b) -> t a -> Slist b
S.concatMap
            (\iId :: Inspection
iId -> ExtensionsResult -> Inspection -> HieFile -> Observations
analysisByInspection ExtensionsResult
fileInfoMergedExtensions Inspection
iId HieFile
hieFile)
            [Inspection]
ins
    let (ignoredObs :: Observations
ignoredObs, fileInfoObservations :: 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
    String -> FileInfo -> State Analysis ()
updateFileMap String
hie_hs_file $WFileInfo :: String
-> ModuleName
-> Int
-> Either ExtensionsError ParsedExtensions
-> Either ExtensionsError ParsedExtensions
-> ExtensionsResult
-> Observations
-> FileInfo
FileInfo{..}
    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