{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE LambdaCase #-}
module Camfort.Analysis.Simple
( countVariableDeclarations
, checkImplicitNone
, ImplicitNoneReport(..)
, checkAllocateStatements
, checkFloatingPointUse
, checkModuleUse
, checkArrayUse )
where
import Prelude hiding (unlines)
import Control.Monad
import Control.DeepSeq
import Data.Data
import Data.Function (on)
import Data.Maybe (catMaybes, fromMaybe, listToMaybe, mapMaybe)
import qualified Data.Set as S
import qualified Data.IntSet as IS
import qualified Data.Map.Strict as M
import qualified Data.IntMap.Strict as IM
import qualified Data.Semigroup as SG
import Data.Monoid ((<>))
import Data.Generics.Uniplate.Operations
import qualified Data.Text.Lazy.Builder as Builder
import Data.Text (unlines, intercalate, pack)
import Data.List (sort, nub, nubBy, tails)
import GHC.Generics
import qualified Data.List.NonEmpty as NE
import Data.Graph.Inductive
import qualified Language.Fortran.AST as F
import qualified Language.Fortran.Analysis.SemanticTypes as FAS
import qualified Language.Fortran.Util.Position as F
import qualified Language.Fortran.Analysis as F
import qualified Language.Fortran.Analysis.DataFlow as F
import qualified Language.Fortran.Analysis.BBlocks as F
import Language.Fortran.Util.ModFile
import Camfort.Analysis (analysisModFiles, ExitCodeOfReport(..), atSpanned, atSpannedInFile, Origin
, logError, describe, describeBuilder
, PureAnalysis, Describe )
import Camfort.Analysis.ModFile (withCombinedEnvironment)
newtype VarCountReport = VarCountReport Int deriving (forall x. VarCountReport -> Rep VarCountReport x)
-> (forall x. Rep VarCountReport x -> VarCountReport)
-> Generic VarCountReport
forall x. Rep VarCountReport x -> VarCountReport
forall x. VarCountReport -> Rep VarCountReport x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. VarCountReport -> Rep VarCountReport x
from :: forall x. VarCountReport -> Rep VarCountReport x
$cto :: forall x. Rep VarCountReport x -> VarCountReport
to :: forall x. Rep VarCountReport x -> VarCountReport
Generic
instance NFData VarCountReport
instance ExitCodeOfReport VarCountReport where
exitCodeOf :: VarCountReport -> Int
exitCodeOf VarCountReport
_ = Int
0
instance Describe VarCountReport where
describeBuilder :: VarCountReport -> Builder
describeBuilder (VarCountReport Int
c) = Text -> Builder
Builder.fromText (Text -> Builder) -> Text -> Builder
forall a b. (a -> b) -> a -> b
$ Int -> Text
forall a. Describe a => a -> Text
describe Int
c
countVariableDeclarations :: forall a. Data a => F.ProgramFile a -> PureAnalysis () () VarCountReport
countVariableDeclarations :: forall a.
Data a =>
ProgramFile a -> PureAnalysis () () VarCountReport
countVariableDeclarations ProgramFile a
pf = VarCountReport -> PureAnalysis () () VarCountReport
forall a. a -> AnalysisT () () Identity a
forall (m :: * -> *) a. Monad m => a -> m a
return (VarCountReport -> PureAnalysis () () VarCountReport)
-> (Int -> VarCountReport)
-> Int
-> PureAnalysis () () VarCountReport
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> VarCountReport
VarCountReport (Int -> PureAnalysis () () VarCountReport)
-> Int -> PureAnalysis () () VarCountReport
forall a b. (a -> b) -> a -> b
$ [Declarator a] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length (ProgramFile a -> [Declarator a]
forall from to. Biplate from to => from -> [to]
universeBi ProgramFile a
pf :: [F.Declarator a])
type PULoc = (F.ProgramUnitName, Origin)
data ImplicitNoneReport
= ImplicitNoneReport [PULoc]
deriving (forall x. ImplicitNoneReport -> Rep ImplicitNoneReport x)
-> (forall x. Rep ImplicitNoneReport x -> ImplicitNoneReport)
-> Generic ImplicitNoneReport
forall x. Rep ImplicitNoneReport x -> ImplicitNoneReport
forall x. ImplicitNoneReport -> Rep ImplicitNoneReport x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. ImplicitNoneReport -> Rep ImplicitNoneReport x
from :: forall x. ImplicitNoneReport -> Rep ImplicitNoneReport x
$cto :: forall x. Rep ImplicitNoneReport x -> ImplicitNoneReport
to :: forall x. Rep ImplicitNoneReport x -> ImplicitNoneReport
Generic
instance NFData ImplicitNoneReport
instance SG.Semigroup ImplicitNoneReport where
ImplicitNoneReport [PULoc]
r1 <> :: ImplicitNoneReport -> ImplicitNoneReport -> ImplicitNoneReport
<> ImplicitNoneReport [PULoc]
r2 = [PULoc] -> ImplicitNoneReport
ImplicitNoneReport ([PULoc] -> ImplicitNoneReport) -> [PULoc] -> ImplicitNoneReport
forall a b. (a -> b) -> a -> b
$ [PULoc]
r1 [PULoc] -> [PULoc] -> [PULoc]
forall a. [a] -> [a] -> [a]
++ [PULoc]
r2
instance Monoid ImplicitNoneReport where
mempty :: ImplicitNoneReport
mempty = [PULoc] -> ImplicitNoneReport
ImplicitNoneReport []
mappend :: ImplicitNoneReport -> ImplicitNoneReport -> ImplicitNoneReport
mappend = ImplicitNoneReport -> ImplicitNoneReport -> ImplicitNoneReport
forall a. Semigroup a => a -> a -> a
(SG.<>)
checkImplicitNone :: forall a. Data a => Bool -> F.ProgramFile a -> PureAnalysis String () ImplicitNoneReport
checkImplicitNone :: forall a.
Data a =>
Bool -> ProgramFile a -> PureAnalysis String () ImplicitNoneReport
checkImplicitNone Bool
allPU ProgramFile a
pf = do
[ImplicitNoneReport]
checkedPUs <- if Bool
allPU
then [PureAnalysis String () ImplicitNoneReport]
-> AnalysisT String () Identity [ImplicitNoneReport]
forall (t :: * -> *) (m :: * -> *) a.
(Traversable t, Monad m) =>
t (m a) -> m (t a)
forall (m :: * -> *) a. Monad m => [m a] -> m [a]
sequence [ ProgramUnit a -> PureAnalysis String () ImplicitNoneReport
forall {m :: * -> *} {e} {w}.
MonadLogger e w m =>
ProgramUnit a -> m ImplicitNoneReport
puHelper ProgramUnit a
pu | ProgramUnit a
pu <- ProgramFile a -> [ProgramUnit a]
forall from to. Biplate from to => from -> [to]
universeBi ProgramFile a
pf :: [F.ProgramUnit a] ]
else [PureAnalysis String () ImplicitNoneReport]
-> AnalysisT String () Identity [ImplicitNoneReport]
forall (t :: * -> *) (m :: * -> *) a.
(Traversable t, Monad m) =>
t (m a) -> m (t a)
forall (m :: * -> *) a. Monad m => [m a] -> m [a]
sequence ( [ ProgramUnit a -> PureAnalysis String () ImplicitNoneReport
forall {m :: * -> *} {e} {w}.
MonadLogger e w m =>
ProgramUnit a -> m ImplicitNoneReport
puHelper ProgramUnit a
pu | ProgramUnit a
pu <- ProgramFile a -> [ProgramUnit a]
forall from to. Biplate from to => from -> [to]
childrenBi ProgramFile a
pf :: [F.ProgramUnit a] ] [PureAnalysis String () ImplicitNoneReport]
-> [PureAnalysis String () ImplicitNoneReport]
-> [PureAnalysis String () ImplicitNoneReport]
forall a. [a] -> [a] -> [a]
++
[ ProgramUnit a -> PureAnalysis String () ImplicitNoneReport
forall {m :: * -> *} {e} {w}.
MonadLogger e w m =>
ProgramUnit a -> m ImplicitNoneReport
puHelper ProgramUnit a
pu | int :: Block a
int@(F.BlInterface {}) <- ProgramFile a -> [Block a]
forall from to. Biplate from to => from -> [to]
universeBi ProgramFile a
pf :: [F.Block a]
, ProgramUnit a
pu <- Block a -> [ProgramUnit a]
forall from to. Biplate from to => from -> [to]
childrenBi Block a
int :: [F.ProgramUnit a] ] )
[ImplicitNoneReport]
-> (ImplicitNoneReport -> AnalysisT String () Identity ())
-> AnalysisT String () Identity ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ [ImplicitNoneReport]
checkedPUs ((ImplicitNoneReport -> AnalysisT String () Identity ())
-> AnalysisT String () Identity ())
-> (ImplicitNoneReport -> AnalysisT String () Identity ())
-> AnalysisT String () Identity ()
forall a b. (a -> b) -> a -> b
$ \ ImplicitNoneReport
r -> case ImplicitNoneReport
r of
ImplicitNoneReport [(F.Named String
name, Origin
orig)] -> Origin -> String -> AnalysisT String () Identity ()
forall e w (m :: * -> *). MonadLogger e w m => Origin -> e -> m ()
logError Origin
orig String
name
ImplicitNoneReport
_ -> () -> AnalysisT String () Identity ()
forall a. a -> AnalysisT String () Identity a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
ImplicitNoneReport -> PureAnalysis String () ImplicitNoneReport
forall a. a -> AnalysisT String () Identity a
forall (m :: * -> *) a. Monad m => a -> m a
return (ImplicitNoneReport -> PureAnalysis String () ImplicitNoneReport)
-> ImplicitNoneReport -> PureAnalysis String () ImplicitNoneReport
forall a b. NFData a => (a -> b) -> a -> b
$!! [ImplicitNoneReport] -> ImplicitNoneReport
forall a. Monoid a => [a] -> a
mconcat [ImplicitNoneReport]
checkedPUs
where
isUseStmt :: Block a -> Bool
isUseStmt (F.BlStatement a
_ SrcSpan
_ Maybe (Expression a)
_ (F.StUse {})) = Bool
True
isUseStmt Block a
_ = Bool
False
isComment :: Block a -> Bool
isComment (F.BlComment {}) = Bool
True
isComment Block a
_ = Bool
False
isUseOrComment :: Block a -> Bool
isUseOrComment Block a
b = Block a -> Bool
forall {a}. Block a -> Bool
isUseStmt Block a
b Bool -> Bool -> Bool
|| Block a -> Bool
forall {a}. Block a -> Bool
isComment Block a
b
isImplicitNone :: Block a -> Bool
isImplicitNone (F.BlStatement a
_ SrcSpan
_ Maybe (Expression a)
_ (F.StImplicit a
_ SrcSpan
_ Maybe (AList ImpList a)
Nothing)) = Bool
True; isImplicitNone Block a
_ = Bool
False
isImplicitSome :: Block a -> Bool
isImplicitSome (F.BlStatement a
_ SrcSpan
_ Maybe (Expression a)
_ (F.StImplicit a
_ SrcSpan
_ (Just AList ImpList a
_))) = Bool
True; isImplicitSome Block a
_ = Bool
False
checkPU :: F.ProgramUnit a -> Bool
checkPU :: ProgramUnit a -> Bool
checkPU ProgramUnit a
pu = case ProgramUnit a
pu of
F.PUMain a
_ SrcSpan
_ Maybe String
_ [Block a]
bs Maybe [ProgramUnit a]
_ -> [Block a] -> Bool
forall {a}. [Block a] -> Bool
checkBlocks [Block a]
bs
F.PUModule a
_ SrcSpan
_ String
_ [Block a]
bs Maybe [ProgramUnit a]
_ -> [Block a] -> Bool
forall {a}. [Block a] -> Bool
checkBlocks [Block a]
bs
F.PUSubroutine a
_ SrcSpan
_ PrefixSuffix a
_ String
_ Maybe (AList Expression a)
_ [Block a]
bs Maybe [ProgramUnit a]
_ -> [Block a] -> Bool
forall {a}. [Block a] -> Bool
checkBlocks [Block a]
bs
F.PUFunction a
_ SrcSpan
_ Maybe (TypeSpec a)
_ PrefixSuffix a
_ String
_ Maybe (AList Expression a)
_ Maybe (Expression a)
_ [Block a]
bs Maybe [ProgramUnit a]
_ -> [Block a] -> Bool
forall {a}. [Block a] -> Bool
checkBlocks [Block a]
bs
ProgramUnit a
_ -> Bool
True
checkBlocks :: [Block a] -> Bool
checkBlocks [Block a]
bs = (Block a -> Bool) -> [Block a] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (Bool -> Bool
not (Bool -> Bool) -> (Block a -> Bool) -> Block a -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Block a -> Bool
forall {a}. Block a -> Bool
isImplicitSome) [Block a]
bs Bool -> Bool -> Bool
&& (Block a -> Bool) -> [Block a] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all Block a -> Bool
forall {a}. Block a -> Bool
isUseOrComment [Block a]
useStmts Bool -> Bool -> Bool
&& Bool -> Bool
not ([Block a] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Block a]
rest) Bool -> Bool -> Bool
&& (Block a -> Bool) -> [Block a] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (Bool -> Bool
not (Bool -> Bool) -> (Block a -> Bool) -> Block a -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Block a -> Bool
forall {a}. Block a -> Bool
isUseStmt) [Block a]
rest
where
([Block a]
useStmts, [Block a]
rest) = (Block a -> Bool) -> [Block a] -> ([Block a], [Block a])
forall a. (a -> Bool) -> [a] -> ([a], [a])
break Block a -> Bool
forall {a}. Block a -> Bool
isImplicitNone [Block a]
bs
puHelper :: ProgramUnit a -> m ImplicitNoneReport
puHelper ProgramUnit a
pu
| ProgramUnit a -> Bool
checkPU ProgramUnit a
pu = ImplicitNoneReport -> m ImplicitNoneReport
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return ImplicitNoneReport
forall a. Monoid a => a
mempty
| Bool
otherwise = (Origin -> ImplicitNoneReport) -> m Origin -> m ImplicitNoneReport
forall a b. (a -> b) -> m a -> m b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\ Origin
o -> [PULoc] -> ImplicitNoneReport
ImplicitNoneReport [(ProgramUnit a -> ProgramUnitName
forall a. Named a => a -> ProgramUnitName
F.getName ProgramUnit a
pu, Origin
o)]) (m Origin -> m ImplicitNoneReport)
-> m Origin -> m ImplicitNoneReport
forall a b. (a -> b) -> a -> b
$ ProgramUnit a -> m Origin
forall e w (m :: * -> *) a.
(MonadLogger e w m, Spanned a) =>
a -> m Origin
atSpanned ProgramUnit a
pu
instance Describe ImplicitNoneReport where
describeBuilder :: ImplicitNoneReport -> Builder
describeBuilder (ImplicitNoneReport [PULoc]
results)
| [PULoc] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [PULoc]
results = Builder
"no cases detected"
| [PULoc] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null ([PULoc] -> [PULoc]
forall a. HasCallStack => [a] -> [a]
tail [PULoc]
results) = Builder
"1 case detected"
| Bool
otherwise = Text -> Builder
Builder.fromText (Text -> Builder) -> Text -> Builder
forall a b. (a -> b) -> a -> b
$ Int -> Text
forall a. Describe a => a -> Text
describe ([PULoc] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [PULoc]
results) Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" cases detected"
instance ExitCodeOfReport ImplicitNoneReport where
exitCodeOf :: ImplicitNoneReport -> Int
exitCodeOf (ImplicitNoneReport []) = Int
0
exitCodeOf (ImplicitNoneReport [PULoc]
_) = Int
1
data CheckAllocReport
= CheckAllocReport { CheckAllocReport -> [(String, PULoc)]
unbalancedAllocs :: [(F.Name, PULoc)]
, CheckAllocReport -> [(String, PULoc)]
outOfOrder :: [(F.Name, PULoc)]}
deriving (forall x. CheckAllocReport -> Rep CheckAllocReport x)
-> (forall x. Rep CheckAllocReport x -> CheckAllocReport)
-> Generic CheckAllocReport
forall x. Rep CheckAllocReport x -> CheckAllocReport
forall x. CheckAllocReport -> Rep CheckAllocReport x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. CheckAllocReport -> Rep CheckAllocReport x
from :: forall x. CheckAllocReport -> Rep CheckAllocReport x
$cto :: forall x. Rep CheckAllocReport x -> CheckAllocReport
to :: forall x. Rep CheckAllocReport x -> CheckAllocReport
Generic
instance NFData CheckAllocReport
instance SG.Semigroup CheckAllocReport where
CheckAllocReport [(String, PULoc)]
a1 [(String, PULoc)]
b1 <> :: CheckAllocReport -> CheckAllocReport -> CheckAllocReport
<> CheckAllocReport [(String, PULoc)]
a2 [(String, PULoc)]
b2 = [(String, PULoc)] -> [(String, PULoc)] -> CheckAllocReport
CheckAllocReport ([(String, PULoc)]
a1 [(String, PULoc)] -> [(String, PULoc)] -> [(String, PULoc)]
forall a. [a] -> [a] -> [a]
++ [(String, PULoc)]
a2) ([(String, PULoc)]
b1 [(String, PULoc)] -> [(String, PULoc)] -> [(String, PULoc)]
forall a. [a] -> [a] -> [a]
++ [(String, PULoc)]
b2)
instance Monoid CheckAllocReport where
mempty :: CheckAllocReport
mempty = [(String, PULoc)] -> [(String, PULoc)] -> CheckAllocReport
CheckAllocReport [] []
mappend :: CheckAllocReport -> CheckAllocReport -> CheckAllocReport
mappend = CheckAllocReport -> CheckAllocReport -> CheckAllocReport
forall a. Semigroup a => a -> a -> a
(SG.<>)
checkAllocateStatements :: forall a. Data a => F.ProgramFile a -> PureAnalysis String () CheckAllocReport
checkAllocateStatements :: forall a.
Data a =>
ProgramFile a -> PureAnalysis String () CheckAllocReport
checkAllocateStatements ProgramFile a
pf = do
let F.ProgramFile F.MetaInfo { miFilename :: MetaInfo -> String
F.miFilename = String
file } [ProgramUnit a]
_ = ProgramFile a
pf
let checkPU :: F.ProgramUnit a -> CheckAllocReport
checkPU :: ProgramUnit a -> CheckAllocReport
checkPU ProgramUnit a
pu = CheckAllocReport {[(String, PULoc)]
unbalancedAllocs :: [(String, PULoc)]
outOfOrder :: [(String, PULoc)]
unbalancedAllocs :: [(String, PULoc)]
outOfOrder :: [(String, PULoc)]
..}
where
allocs :: [(String, PULoc)]
allocs =
[ (String
v, (ProgramUnit a -> ProgramUnitName
forall a. Named a => a -> ProgramUnitName
F.getName ProgramUnit a
pu, String -> Expression a -> Origin
forall a. Spanned a => String -> a -> Origin
atSpannedInFile String
file Expression a
e))
| F.StAllocate a
_ SrcSpan
_ Maybe (TypeSpec a)
_ (F.AList a
_ SrcSpan
_ [Expression a]
es) Maybe (AList AllocOpt a)
_ <- [Block a] -> [Statement a]
forall from to. Biplate from to => from -> [to]
universeBi (ProgramUnit a -> [Block a]
forall a. ProgramUnit a -> [Block a]
F.programUnitBody ProgramUnit a
pu) :: [F.Statement a]
, Expression a
e <- [Expression a]
es
, String
v <- Int -> [String] -> [String]
forall a. Int -> [a] -> [a]
take Int
1 [ String
v | F.ExpValue a
_ SrcSpan
_ (F.ValVariable String
v) <- Expression a -> [Expression a]
forall from to. Biplate from to => from -> [to]
universeBi Expression a
e :: [F.Expression a] ]
]
deallocs :: [(String, PULoc)]
deallocs =
[ (String
v, (ProgramUnit a -> ProgramUnitName
forall a. Named a => a -> ProgramUnitName
F.getName ProgramUnit a
pu, String -> Expression a -> Origin
forall a. Spanned a => String -> a -> Origin
atSpannedInFile String
file Expression a
e))
| F.StDeallocate a
_ SrcSpan
_ (F.AList a
_ SrcSpan
_ [Expression a]
es) Maybe (AList AllocOpt a)
_ <- [Block a] -> [Statement a]
forall from to. Biplate from to => from -> [to]
universeBi (ProgramUnit a -> [Block a]
forall a. ProgramUnit a -> [Block a]
F.programUnitBody ProgramUnit a
pu) :: [F.Statement a]
, Expression a
e <- [Expression a]
es
, String
v <- Int -> [String] -> [String]
forall a. Int -> [a] -> [a]
take Int
1 [ String
v | F.ExpValue a
_ SrcSpan
_ (F.ValVariable String
v) <- Expression a -> [Expression a]
forall from to. Biplate from to => from -> [to]
universeBi Expression a
e :: [F.Expression a] ]
]
isDealloced :: String -> Bool
isDealloced String
v = Bool -> Bool
not (Bool -> Bool)
-> ([(String, PULoc)] -> Bool) -> [(String, PULoc)] -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [(String, PULoc)] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null ([(String, PULoc)] -> Bool) -> [(String, PULoc)] -> Bool
forall a b. (a -> b) -> a -> b
$ ((String, PULoc) -> Bool) -> [(String, PULoc)] -> [(String, PULoc)]
forall a. (a -> Bool) -> [a] -> [a]
filter ((String -> String -> Bool
forall a. Eq a => a -> a -> Bool
==String
v) (String -> Bool)
-> ((String, PULoc) -> String) -> (String, PULoc) -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (String, PULoc) -> String
forall a b. (a, b) -> a
fst) [(String, PULoc)]
deallocs
unbalancedAllocs :: [(String, PULoc)]
unbalancedAllocs = ((String, PULoc) -> Bool) -> [(String, PULoc)] -> [(String, PULoc)]
forall a. (a -> Bool) -> [a] -> [a]
filter (Bool -> Bool
not (Bool -> Bool)
-> ((String, PULoc) -> Bool) -> (String, PULoc) -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Bool
isDealloced (String -> Bool)
-> ((String, PULoc) -> String) -> (String, PULoc) -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (String, PULoc) -> String
forall a b. (a, b) -> a
fst) [(String, PULoc)]
allocs
outOfOrder :: [(String, PULoc)]
outOfOrder = [[(String, PULoc)]] -> [(String, PULoc)]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat ([[(String, PULoc)]] -> [(String, PULoc)])
-> [[(String, PULoc)]] -> [(String, PULoc)]
forall a b. (a -> b) -> a -> b
$ ((String, PULoc) -> (String, PULoc) -> [(String, PULoc)])
-> [(String, PULoc)] -> [(String, PULoc)] -> [[(String, PULoc)]]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith (\ (String, PULoc)
v1 (String, PULoc)
v2 -> if (String, PULoc) -> String
forall a b. (a, b) -> a
fst (String, PULoc)
v1 String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== (String, PULoc) -> String
forall a b. (a, b) -> a
fst (String, PULoc)
v2 then [] else [(String, PULoc)
v1, (String, PULoc)
v2]) (((String, PULoc) -> (String, PULoc) -> Bool)
-> [(String, PULoc)] -> [(String, PULoc)]
forall a. (a -> a -> Bool) -> [a] -> [a]
nubBy (String -> String -> Bool
forall a. Eq a => a -> a -> Bool
(==) (String -> String -> Bool)
-> ((String, PULoc) -> String)
-> (String, PULoc)
-> (String, PULoc)
-> Bool
forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
`on` (String, PULoc) -> String
forall a b. (a, b) -> a
fst) [(String, PULoc)]
allocs) (((String, PULoc) -> (String, PULoc) -> Bool)
-> [(String, PULoc)] -> [(String, PULoc)]
forall a. (a -> a -> Bool) -> [a] -> [a]
nubBy (String -> String -> Bool
forall a. Eq a => a -> a -> Bool
(==) (String -> String -> Bool)
-> ((String, PULoc) -> String)
-> (String, PULoc)
-> (String, PULoc)
-> Bool
forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
`on` (String, PULoc) -> String
forall a b. (a, b) -> a
fst) ([(String, PULoc)] -> [(String, PULoc)])
-> [(String, PULoc)] -> [(String, PULoc)]
forall a b. (a -> b) -> a -> b
$ [(String, PULoc)] -> [(String, PULoc)]
forall a. [a] -> [a]
reverse [(String, PULoc)]
deallocs)
let reports :: [CheckAllocReport]
reports = (ProgramUnit a -> CheckAllocReport)
-> [ProgramUnit a] -> [CheckAllocReport]
forall a b. (a -> b) -> [a] -> [b]
map ProgramUnit a -> CheckAllocReport
checkPU (ProgramFile a -> [ProgramUnit a]
forall from to. Biplate from to => from -> [to]
universeBi ProgramFile a
pf)
CheckAllocReport -> PureAnalysis String () CheckAllocReport
forall a. a -> AnalysisT String () Identity a
forall (m :: * -> *) a. Monad m => a -> m a
return (CheckAllocReport -> PureAnalysis String () CheckAllocReport)
-> CheckAllocReport -> PureAnalysis String () CheckAllocReport
forall a b. NFData a => (a -> b) -> a -> b
$!! [CheckAllocReport] -> CheckAllocReport
forall a. Monoid a => [a] -> a
mconcat [CheckAllocReport]
reports
instance Describe CheckAllocReport where
describeBuilder :: CheckAllocReport -> Builder
describeBuilder (CheckAllocReport {[(String, PULoc)]
unbalancedAllocs :: CheckAllocReport -> [(String, PULoc)]
outOfOrder :: CheckAllocReport -> [(String, PULoc)]
unbalancedAllocs :: [(String, PULoc)]
outOfOrder :: [(String, PULoc)]
..})
| [(String, PULoc)] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null ([(String, PULoc)]
unbalancedAllocs [(String, PULoc)] -> [(String, PULoc)] -> [(String, PULoc)]
forall a. [a] -> [a] -> [a]
++ [(String, PULoc)]
outOfOrder) = Builder
"no cases detected"
| Bool
otherwise = Text -> Builder
Builder.fromText (Text -> Builder) -> ([Text] -> Text) -> [Text] -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Text] -> Text
unlines ([Text] -> Builder) -> [Text] -> Builder
forall a b. (a -> b) -> a -> b
$
[ Origin -> Text
forall a. Describe a => a -> Text
describe Origin
orig Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" unbalanced allocation or deallocation for " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> String -> Text
pack String
name
| (String
name, (ProgramUnitName
_, Origin
orig)) <- [(String, PULoc)]
unbalancedAllocs ] [Text] -> [Text] -> [Text]
forall a. [a] -> [a] -> [a]
++
[ Origin -> Text
forall a. Describe a => a -> Text
describe Origin
orig Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" out-of-order (de)allocation " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> String -> Text
pack String
name
| (String
name, (ProgramUnitName
_, Origin
orig)) <- [(String, PULoc)]
outOfOrder ]
instance ExitCodeOfReport CheckAllocReport where
exitCodeOf :: CheckAllocReport -> Int
exitCodeOf (CheckAllocReport {[(String, PULoc)]
unbalancedAllocs :: CheckAllocReport -> [(String, PULoc)]
outOfOrder :: CheckAllocReport -> [(String, PULoc)]
unbalancedAllocs :: [(String, PULoc)]
outOfOrder :: [(String, PULoc)]
..})
| [(String, PULoc)] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null ([(String, PULoc)]
unbalancedAllocs [(String, PULoc)] -> [(String, PULoc)] -> [(String, PULoc)]
forall a. [a] -> [a] -> [a]
++ [(String, PULoc)]
outOfOrder) = Int
0
| Bool
otherwise = Int
1
data CheckFPReport
= CheckFPReport { CheckFPReport -> [PULoc]
badEquality :: [PULoc] }
deriving (forall x. CheckFPReport -> Rep CheckFPReport x)
-> (forall x. Rep CheckFPReport x -> CheckFPReport)
-> Generic CheckFPReport
forall x. Rep CheckFPReport x -> CheckFPReport
forall x. CheckFPReport -> Rep CheckFPReport x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. CheckFPReport -> Rep CheckFPReport x
from :: forall x. CheckFPReport -> Rep CheckFPReport x
$cto :: forall x. Rep CheckFPReport x -> CheckFPReport
to :: forall x. Rep CheckFPReport x -> CheckFPReport
Generic
instance NFData CheckFPReport
instance SG.Semigroup CheckFPReport where
CheckFPReport [PULoc]
a1 <> :: CheckFPReport -> CheckFPReport -> CheckFPReport
<> CheckFPReport [PULoc]
a2 = [PULoc] -> CheckFPReport
CheckFPReport ([PULoc]
a1 [PULoc] -> [PULoc] -> [PULoc]
forall a. [a] -> [a] -> [a]
++ [PULoc]
a2)
instance Monoid CheckFPReport where
mempty :: CheckFPReport
mempty = [PULoc] -> CheckFPReport
CheckFPReport []
mappend :: CheckFPReport -> CheckFPReport -> CheckFPReport
mappend = CheckFPReport -> CheckFPReport -> CheckFPReport
forall a. Semigroup a => a -> a -> a
(SG.<>)
checkFloatingPointUse :: forall a. Data a => F.ProgramFile a -> PureAnalysis String () CheckFPReport
checkFloatingPointUse :: forall a.
Data a =>
ProgramFile a -> PureAnalysis String () CheckFPReport
checkFloatingPointUse ProgramFile a
pf = do
let F.ProgramFile F.MetaInfo { miFilename :: MetaInfo -> String
F.miFilename = String
file } [ProgramUnit a]
_ = ProgramFile a
pf
ModFiles
mfs <- AnalysisT String () Identity ModFiles
forall e w (m :: * -> *). MonadAnalysis e w m => m ModFiles
analysisModFiles
let (ProgramFile (Analysis a)
pf', ModuleMap
_, TypeEnv
_) = ModFiles
-> ProgramFile a -> (ProgramFile (Analysis a), ModuleMap, TypeEnv)
forall a.
Data a =>
ModFiles
-> ProgramFile a -> (ProgramFile (Analysis a), ModuleMap, TypeEnv)
withCombinedEnvironment ModFiles
mfs ProgramFile a
pf
let pvm :: ParamVarMap
pvm = ModFiles -> ParamVarMap
combinedParamVarMap ModFiles
mfs
let pf'' :: ProgramFile (Analysis a)
pf'' = ProgramFile (Analysis a) -> ProgramFile (Analysis a)
forall a.
Data a =>
ProgramFile (Analysis a) -> ProgramFile (Analysis a)
F.analyseConstExps (ProgramFile (Analysis a) -> ProgramFile (Analysis a))
-> (ProgramFile (Analysis a) -> ProgramFile (Analysis a))
-> ProgramFile (Analysis a)
-> ProgramFile (Analysis a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ParamVarMap -> ProgramFile (Analysis a) -> ProgramFile (Analysis a)
forall a.
Data a =>
ParamVarMap -> ProgramFile (Analysis a) -> ProgramFile (Analysis a)
F.analyseParameterVars ParamVarMap
pvm (ProgramFile (Analysis a) -> ProgramFile (Analysis a))
-> (ProgramFile (Analysis a) -> ProgramFile (Analysis a))
-> ProgramFile (Analysis a)
-> ProgramFile (Analysis a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ProgramFile (Analysis a) -> ProgramFile (Analysis a)
forall a.
Data a =>
ProgramFile (Analysis a) -> ProgramFile (Analysis a)
F.analyseBBlocks (ProgramFile (Analysis a) -> ProgramFile (Analysis a))
-> ProgramFile (Analysis a) -> ProgramFile (Analysis a)
forall a b. (a -> b) -> a -> b
$ ProgramFile (Analysis a)
pf'
let checkPU :: F.ProgramUnit (F.Analysis a) -> CheckFPReport
checkPU :: ProgramUnit (Analysis a) -> CheckFPReport
checkPU ProgramUnit (Analysis a)
pu = CheckFPReport {[PULoc]
badEquality :: [PULoc]
badEquality :: [PULoc]
..}
where
candidates :: [F.Expression (F.Analysis a)]
candidates :: [Expression (Analysis a)]
candidates = [ Expression (Analysis a)
e | e :: Expression (Analysis a)
e@(F.ExpBinary Analysis a
_ SrcSpan
_ BinaryOp
op Expression (Analysis a)
x Expression (Analysis a)
y) <- [Block (Analysis a)] -> [Expression (Analysis a)]
forall from to. Biplate from to => from -> [to]
universeBi (ProgramUnit (Analysis a) -> [Block (Analysis a)]
forall a. ProgramUnit a -> [Block a]
F.programUnitBody ProgramUnit (Analysis a)
pu)
, BinaryOp
op BinaryOp -> [BinaryOp] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [BinaryOp
F.EQ, BinaryOp
F.NE]
, Just (F.IDType (Just SemType
st) Maybe ConstructType
_) <- [Analysis a -> Maybe IDType
forall a. Analysis a -> Maybe IDType
F.idType (Expression (Analysis a) -> Analysis a
forall a. Expression a -> a
forall (f :: * -> *) a. Annotated f => f a -> a
F.getAnnotation Expression (Analysis a)
x), Analysis a -> Maybe IDType
forall a. Analysis a -> Maybe IDType
F.idType (Expression (Analysis a) -> Analysis a
forall a. Expression a -> a
forall (f :: * -> *) a. Annotated f => f a -> a
F.getAnnotation Expression (Analysis a)
y)]
, SemType -> Bool
isFloatingPointType SemType
st ]
badEquality :: [PULoc]
badEquality = [PULoc] -> [PULoc]
forall a. Eq a => [a] -> [a]
nub [ (ProgramUnit (Analysis a) -> ProgramUnitName
forall a. Named a => a -> ProgramUnitName
F.getName ProgramUnit (Analysis a)
pu, String -> Expression (Analysis a) -> Origin
forall a. Spanned a => String -> a -> Origin
atSpannedInFile String
file Expression (Analysis a)
e) | Expression (Analysis a)
e <- [Expression (Analysis a)]
candidates ]
let reports :: [CheckFPReport]
reports = (ProgramUnit (Analysis a) -> CheckFPReport)
-> [ProgramUnit (Analysis a)] -> [CheckFPReport]
forall a b. (a -> b) -> [a] -> [b]
map ProgramUnit (Analysis a) -> CheckFPReport
checkPU (ProgramFile (Analysis a) -> [ProgramUnit (Analysis a)]
forall from to. Biplate from to => from -> [to]
universeBi ProgramFile (Analysis a)
pf'')
CheckFPReport -> PureAnalysis String () CheckFPReport
forall a. a -> AnalysisT String () Identity a
forall (m :: * -> *) a. Monad m => a -> m a
return (CheckFPReport -> PureAnalysis String () CheckFPReport)
-> CheckFPReport -> PureAnalysis String () CheckFPReport
forall a b. NFData a => (a -> b) -> a -> b
$!! [CheckFPReport] -> CheckFPReport
forall a. Monoid a => [a] -> a
mconcat [CheckFPReport]
reports
isFloatingPointType :: FAS.SemType -> Bool
isFloatingPointType :: SemType -> Bool
isFloatingPointType = \case
FAS.TReal Int
_ -> Bool
True
FAS.TComplex Int
_ -> Bool
True
SemType
_ -> Bool
False
instance Describe CheckFPReport where
describeBuilder :: CheckFPReport -> Builder
describeBuilder (CheckFPReport {[PULoc]
badEquality :: CheckFPReport -> [PULoc]
badEquality :: [PULoc]
..})
| [PULoc] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null ([PULoc]
badEquality) = Builder
"no cases detected"
| Bool
otherwise = Text -> Builder
Builder.fromText (Text -> Builder) -> ([Text] -> Text) -> [Text] -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Text] -> Text
unlines ([Text] -> Builder) -> [Text] -> Builder
forall a b. (a -> b) -> a -> b
$
[ Origin -> Text
forall a. Describe a => a -> Text
describe Origin
orig Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" equality operation used on floating-point numbers."
| (ProgramUnitName
_, Origin
orig) <- [PULoc]
badEquality ]
instance ExitCodeOfReport CheckFPReport where
exitCodeOf :: CheckFPReport -> Int
exitCodeOf (CheckFPReport {[PULoc]
badEquality :: CheckFPReport -> [PULoc]
badEquality :: [PULoc]
..})
| [PULoc] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null ([PULoc]
badEquality) = Int
0
| Bool
otherwise = Int
1
data CheckUseReport
= CheckUseReport { CheckUseReport -> [PULoc]
missingOnly :: [PULoc]
, CheckUseReport -> [(String, PULoc)]
duppedOnly :: [(String, PULoc)]
, CheckUseReport -> [(String, PULoc)]
unusedNames :: [(String, PULoc)]
}
deriving (forall x. CheckUseReport -> Rep CheckUseReport x)
-> (forall x. Rep CheckUseReport x -> CheckUseReport)
-> Generic CheckUseReport
forall x. Rep CheckUseReport x -> CheckUseReport
forall x. CheckUseReport -> Rep CheckUseReport x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. CheckUseReport -> Rep CheckUseReport x
from :: forall x. CheckUseReport -> Rep CheckUseReport x
$cto :: forall x. Rep CheckUseReport x -> CheckUseReport
to :: forall x. Rep CheckUseReport x -> CheckUseReport
Generic
instance NFData CheckUseReport
instance SG.Semigroup CheckUseReport where
CheckUseReport [PULoc]
a1 [(String, PULoc)]
b1 [(String, PULoc)]
c1 <> :: CheckUseReport -> CheckUseReport -> CheckUseReport
<> CheckUseReport [PULoc]
a2 [(String, PULoc)]
b2 [(String, PULoc)]
c2 = [PULoc] -> [(String, PULoc)] -> [(String, PULoc)] -> CheckUseReport
CheckUseReport ([PULoc]
a1 [PULoc] -> [PULoc] -> [PULoc]
forall a. [a] -> [a] -> [a]
++ [PULoc]
a2) ([(String, PULoc)]
b1 [(String, PULoc)] -> [(String, PULoc)] -> [(String, PULoc)]
forall a. [a] -> [a] -> [a]
++ [(String, PULoc)]
b2) ([(String, PULoc)]
c1 [(String, PULoc)] -> [(String, PULoc)] -> [(String, PULoc)]
forall a. [a] -> [a] -> [a]
++ [(String, PULoc)]
c2)
instance Monoid CheckUseReport where
mempty :: CheckUseReport
mempty = [PULoc] -> [(String, PULoc)] -> [(String, PULoc)] -> CheckUseReport
CheckUseReport [] [] []
mappend :: CheckUseReport -> CheckUseReport -> CheckUseReport
mappend = CheckUseReport -> CheckUseReport -> CheckUseReport
forall a. Semigroup a => a -> a -> a
(SG.<>)
checkModuleUse :: forall a. Data a => F.ProgramFile a -> PureAnalysis String () CheckUseReport
checkModuleUse :: forall a.
Data a =>
ProgramFile a -> PureAnalysis String () CheckUseReport
checkModuleUse ProgramFile a
pf = do
let F.ProgramFile F.MetaInfo { miFilename :: MetaInfo -> String
F.miFilename = String
file } [ProgramUnit a]
_ = ProgramFile a
pf
ModFiles
mfs <- AnalysisT String () Identity ModFiles
forall e w (m :: * -> *). MonadAnalysis e w m => m ModFiles
analysisModFiles
let (ProgramFile (Analysis a)
pf', ModuleMap
_, TypeEnv
_) = ModFiles
-> ProgramFile a -> (ProgramFile (Analysis a), ModuleMap, TypeEnv)
forall a.
Data a =>
ModFiles
-> ProgramFile a -> (ProgramFile (Analysis a), ModuleMap, TypeEnv)
withCombinedEnvironment ModFiles
mfs ProgramFile a
pf
let checkPU :: F.ProgramUnit (F.Analysis a) -> CheckUseReport
checkPU :: ProgramUnit (Analysis a) -> CheckUseReport
checkPU ProgramUnit (Analysis a)
pu = CheckUseReport {[(String, PULoc)]
[PULoc]
missingOnly :: [PULoc]
duppedOnly :: [(String, PULoc)]
unusedNames :: [(String, PULoc)]
missingOnly :: [PULoc]
duppedOnly :: [(String, PULoc)]
unusedNames :: [(String, PULoc)]
..}
where
statements :: [F.Statement (F.Analysis a)]
statements :: [Statement (Analysis a)]
statements = [Block (Analysis a)] -> [Statement (Analysis a)]
forall from to. Biplate from to => from -> [to]
universeBi (ProgramUnit (Analysis a) -> [Block (Analysis a)]
forall a. ProgramUnit a -> [Block a]
F.programUnitBody ProgramUnit (Analysis a)
pu)
expressions :: [F.Expression (F.Analysis a)]
expressions :: [Expression (Analysis a)]
expressions = ProgramUnit (Analysis a) -> [Expression (Analysis a)]
forall from to. Biplate from to => from -> [to]
universeBi ProgramUnit (Analysis a)
pu
missingOnly :: [PULoc]
missingOnly = [PULoc] -> [PULoc]
forall a. Eq a => [a] -> [a]
nub [ (ProgramUnit (Analysis a) -> ProgramUnitName
forall a. Named a => a -> ProgramUnitName
F.getName ProgramUnit (Analysis a)
pu, String -> Statement (Analysis a) -> Origin
forall a. Spanned a => String -> a -> Origin
atSpannedInFile String
file Statement (Analysis a)
s)
| Statement (Analysis a)
s <- [ Statement (Analysis a)
s | s :: Statement (Analysis a)
s@(F.StUse Analysis a
_ SrcSpan
_ Expression (Analysis a)
_ Maybe ModuleNature
_ Only
F.Permissive Maybe (AList Use (Analysis a))
_) <- [Statement (Analysis a)]
statements ] ]
duppedOnly :: [(String, PULoc)]
duppedOnly = [ (String
n, (ProgramUnit (Analysis a) -> ProgramUnitName
forall a. Named a => a -> ProgramUnitName
F.getName ProgramUnit (Analysis a)
pu, String -> SrcSpan -> Origin
forall a. Spanned a => String -> a -> Origin
atSpannedInFile String
file (SrcSpan -> Origin) -> SrcSpan -> Origin
forall a b. (a -> b) -> a -> b
$ (SrcSpan, SrcSpan) -> SrcSpan
forall a. Spanned a => a -> SrcSpan
F.getSpan (SrcSpan
ss, SrcSpan
ss')))
| F.StUse Analysis a
_ SrcSpan
ss (F.ExpValue Analysis a
_ SrcSpan
_ (F.ValVariable String
n)) Maybe ModuleNature
_ Only
_ Maybe (AList Use (Analysis a))
_:[Statement (Analysis a)]
rest <- [Statement (Analysis a)] -> [[Statement (Analysis a)]]
forall a. [a] -> [[a]]
tails [Statement (Analysis a)]
statements
, F.StUse Analysis a
_ SrcSpan
ss' (F.ExpValue Analysis a
_ SrcSpan
_ (F.ValVariable String
n')) Maybe ModuleNature
_ Only
_ Maybe (AList Use (Analysis a))
_ <- [Statement (Analysis a)]
rest
, String
n String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
n' ]
extractUseName :: Use a -> (String, SrcSpan)
extractUseName (F.UseID a
_ SrcSpan
ss (F.ExpValue a
_ SrcSpan
_ (F.ValVariable String
n))) = (String
n, SrcSpan
ss)
extractUseName (F.UseRename a
_ SrcSpan
ss (F.ExpValue a
_ SrcSpan
_ (F.ValVariable String
n)) Expression a
_) = (String
n, SrcSpan
ss)
extractUseName Use a
u = String -> (String, SrcSpan)
forall a. HasCallStack => String -> a
error (String -> (String, SrcSpan)) -> String -> (String, SrcSpan)
forall a b. (a -> b) -> a -> b
$ String
"checkModuleUse: extractUseName: invalid AST: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Use () -> String
forall a. Show a => a -> String
show ((a -> ()) -> Use a -> Use ()
forall a b. (a -> b) -> Use a -> Use b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (() -> a -> ()
forall a b. a -> b -> a
const ()) Use a
u)
unusedNames :: [(String, PULoc)]
unusedNames = [ (String
n, (ProgramUnit (Analysis a) -> ProgramUnitName
forall a. Named a => a -> ProgramUnitName
F.getName ProgramUnit (Analysis a)
pu, String -> SrcSpan -> Origin
forall a. Spanned a => String -> a -> Origin
atSpannedInFile String
file SrcSpan
ss))
| F.StUse Analysis a
_ SrcSpan
_ Expression (Analysis a)
_ Maybe ModuleNature
_ Only
_ (Just (F.AList Analysis a
_ SrcSpan
_ [Use (Analysis a)]
uses)) <- [Statement (Analysis a)]
statements
, (String
n, SrcSpan
ss) <- (Use (Analysis a) -> (String, SrcSpan))
-> [Use (Analysis a)] -> [(String, SrcSpan)]
forall a b. (a -> b) -> [a] -> [b]
map Use (Analysis a) -> (String, SrcSpan)
forall {a}. Use a -> (String, SrcSpan)
extractUseName [Use (Analysis a)]
uses
, [()] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null (Int -> [()] -> [()]
forall a. Int -> [a] -> [a]
drop Int
1 [ () | F.ExpValue Analysis a
_ SrcSpan
_ (F.ValVariable String
n') <- [Expression (Analysis a)]
expressions, String
n String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
n' ]) ]
let reports :: [CheckUseReport]
reports = (ProgramUnit (Analysis a) -> CheckUseReport)
-> [ProgramUnit (Analysis a)] -> [CheckUseReport]
forall a b. (a -> b) -> [a] -> [b]
map ProgramUnit (Analysis a) -> CheckUseReport
checkPU (ProgramFile (Analysis a) -> [ProgramUnit (Analysis a)]
forall from to. Biplate from to => from -> [to]
universeBi ProgramFile (Analysis a)
pf')
CheckUseReport -> PureAnalysis String () CheckUseReport
forall a. a -> AnalysisT String () Identity a
forall (m :: * -> *) a. Monad m => a -> m a
return (CheckUseReport -> PureAnalysis String () CheckUseReport)
-> CheckUseReport -> PureAnalysis String () CheckUseReport
forall a b. NFData a => (a -> b) -> a -> b
$!! [CheckUseReport] -> CheckUseReport
forall a. Monoid a => [a] -> a
mconcat [CheckUseReport]
reports
instance Describe CheckUseReport where
describeBuilder :: CheckUseReport -> Builder
describeBuilder (CheckUseReport {[(String, PULoc)]
[PULoc]
missingOnly :: CheckUseReport -> [PULoc]
duppedOnly :: CheckUseReport -> [(String, PULoc)]
unusedNames :: CheckUseReport -> [(String, PULoc)]
missingOnly :: [PULoc]
duppedOnly :: [(String, PULoc)]
unusedNames :: [(String, PULoc)]
..})
| [PULoc] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [PULoc]
missingOnly Bool -> Bool -> Bool
&& [(String, PULoc)] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [(String, PULoc)]
duppedOnly Bool -> Bool -> Bool
&& [(String, PULoc)] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [(String, PULoc)]
unusedNames = Builder
"no cases detected"
| Bool
otherwise = Text -> Builder
Builder.fromText (Text -> Builder) -> ([Text] -> Text) -> [Text] -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Text] -> Text
unlines ([Text] -> Builder) -> [Text] -> Builder
forall a b. (a -> b) -> a -> b
$
[ Origin -> Text
forall a. Describe a => a -> Text
describe Origin
orig Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" USE statement missing ONLY attribute."
| (ProgramUnitName
_, Origin
orig) <- [PULoc]
missingOnly ] [Text] -> [Text] -> [Text]
forall a. [a] -> [a] -> [a]
++
[ Origin -> Text
forall a. Describe a => a -> Text
describe Origin
orig Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" multiple USE statements for same module '" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> String -> Text
forall a. Describe a => a -> Text
describe String
name Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"'"
| (String
name, (ProgramUnitName
_, Origin
orig)) <- [(String, PULoc)]
duppedOnly ] [Text] -> [Text] -> [Text]
forall a. [a] -> [a] -> [a]
++
[ Origin -> Text
forall a. Describe a => a -> Text
describe Origin
orig Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" local name '" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> String -> Text
forall a. Describe a => a -> Text
describe String
name Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"' imported but unused in program unit."
| (String
name, (ProgramUnitName
_, Origin
orig)) <- [(String, PULoc)]
unusedNames ]
instance ExitCodeOfReport CheckUseReport where
exitCodeOf :: CheckUseReport -> Int
exitCodeOf (CheckUseReport {[(String, PULoc)]
[PULoc]
missingOnly :: CheckUseReport -> [PULoc]
duppedOnly :: CheckUseReport -> [(String, PULoc)]
unusedNames :: CheckUseReport -> [(String, PULoc)]
missingOnly :: [PULoc]
duppedOnly :: [(String, PULoc)]
unusedNames :: [(String, PULoc)]
..})
| [PULoc] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [PULoc]
missingOnly Bool -> Bool -> Bool
&& [(String, PULoc)] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [(String, PULoc)]
duppedOnly Bool -> Bool -> Bool
&& [(String, PULoc)] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [(String, PULoc)]
unusedNames = Int
0
| Bool
otherwise = Int
1
data CheckArrayReport
= CheckArrayReport { CheckArrayReport -> [([String], PULoc)]
nestedIdx, CheckArrayReport -> [([String], PULoc)]
missingIdx :: [([String], PULoc)] }
deriving (forall x. CheckArrayReport -> Rep CheckArrayReport x)
-> (forall x. Rep CheckArrayReport x -> CheckArrayReport)
-> Generic CheckArrayReport
forall x. Rep CheckArrayReport x -> CheckArrayReport
forall x. CheckArrayReport -> Rep CheckArrayReport x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. CheckArrayReport -> Rep CheckArrayReport x
from :: forall x. CheckArrayReport -> Rep CheckArrayReport x
$cto :: forall x. Rep CheckArrayReport x -> CheckArrayReport
to :: forall x. Rep CheckArrayReport x -> CheckArrayReport
Generic
instance NFData CheckArrayReport
instance SG.Semigroup CheckArrayReport where
CheckArrayReport [([String], PULoc)]
a1 [([String], PULoc)]
b1 <> :: CheckArrayReport -> CheckArrayReport -> CheckArrayReport
<> CheckArrayReport [([String], PULoc)]
a2 [([String], PULoc)]
b2 = [([String], PULoc)] -> [([String], PULoc)] -> CheckArrayReport
CheckArrayReport ([([String], PULoc)]
a1 [([String], PULoc)] -> [([String], PULoc)] -> [([String], PULoc)]
forall a. [a] -> [a] -> [a]
++ [([String], PULoc)]
a2) ([([String], PULoc)]
b1 [([String], PULoc)] -> [([String], PULoc)] -> [([String], PULoc)]
forall a. [a] -> [a] -> [a]
++ [([String], PULoc)]
b2)
instance Monoid CheckArrayReport where
mempty :: CheckArrayReport
mempty = [([String], PULoc)] -> [([String], PULoc)] -> CheckArrayReport
CheckArrayReport [] []
mappend :: CheckArrayReport -> CheckArrayReport -> CheckArrayReport
mappend = CheckArrayReport -> CheckArrayReport -> CheckArrayReport
forall a. Semigroup a => a -> a -> a
(SG.<>)
checkArrayUse :: forall a. Data a => F.ProgramFile a -> PureAnalysis String () CheckArrayReport
checkArrayUse :: forall a.
Data a =>
ProgramFile a -> PureAnalysis String () CheckArrayReport
checkArrayUse ProgramFile a
pf = do
let F.ProgramFile F.MetaInfo { miFilename :: MetaInfo -> String
F.miFilename = String
file } [ProgramUnit a]
_ = ProgramFile a
pf
ModFiles
mfs <- AnalysisT String () Identity ModFiles
forall e w (m :: * -> *). MonadAnalysis e w m => m ModFiles
analysisModFiles
let (ProgramFile (Analysis a)
pf', ModuleMap
_, TypeEnv
_) = ModFiles
-> ProgramFile a -> (ProgramFile (Analysis a), ModuleMap, TypeEnv)
forall a.
Data a =>
ModFiles
-> ProgramFile a -> (ProgramFile (Analysis a), ModuleMap, TypeEnv)
withCombinedEnvironment ModFiles
mfs ProgramFile a
pf
let pvm :: ParamVarMap
pvm = ModFiles -> ParamVarMap
combinedParamVarMap ModFiles
mfs
let pf'' :: ProgramFile (Analysis a)
pf'' = ProgramFile (Analysis a) -> ProgramFile (Analysis a)
forall a.
Data a =>
ProgramFile (Analysis a) -> ProgramFile (Analysis a)
F.analyseConstExps (ProgramFile (Analysis a) -> ProgramFile (Analysis a))
-> (ProgramFile (Analysis a) -> ProgramFile (Analysis a))
-> ProgramFile (Analysis a)
-> ProgramFile (Analysis a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ParamVarMap -> ProgramFile (Analysis a) -> ProgramFile (Analysis a)
forall a.
Data a =>
ParamVarMap -> ProgramFile (Analysis a) -> ProgramFile (Analysis a)
F.analyseParameterVars ParamVarMap
pvm (ProgramFile (Analysis a) -> ProgramFile (Analysis a))
-> (ProgramFile (Analysis a) -> ProgramFile (Analysis a))
-> ProgramFile (Analysis a)
-> ProgramFile (Analysis a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ProgramFile (Analysis a) -> ProgramFile (Analysis a)
forall a.
Data a =>
ProgramFile (Analysis a) -> ProgramFile (Analysis a)
F.analyseBBlocks (ProgramFile (Analysis a) -> ProgramFile (Analysis a))
-> ProgramFile (Analysis a) -> ProgramFile (Analysis a)
forall a b. (a -> b) -> a -> b
$ ProgramFile (Analysis a)
pf'
let bm :: BlockMap a
bm = ProgramFile (Analysis a) -> BlockMap a
forall a. Data a => ProgramFile (Analysis a) -> BlockMap a
F.genBlockMap ProgramFile (Analysis a)
pf''
let dm :: DefMap
dm = BlockMap a -> DefMap
forall a. Data a => BlockMap a -> DefMap
F.genDefMap BlockMap a
bm
let checkPU :: F.ProgramUnit (F.Analysis a) -> CheckArrayReport
checkPU :: ProgramUnit (Analysis a) -> CheckArrayReport
checkPU ProgramUnit (Analysis a)
pu | F.Analysis { bBlocks :: forall a. Analysis a -> Maybe (BBGr (Analysis a))
F.bBlocks = Just BBGr (Analysis a)
_ } <- ProgramUnit (Analysis a) -> Analysis a
forall a. ProgramUnit a -> a
forall (f :: * -> *) a. Annotated f => f a -> a
F.getAnnotation ProgramUnit (Analysis a)
pu = CheckArrayReport {[([String], PULoc)]
nestedIdx :: [([String], PULoc)]
missingIdx :: [([String], PULoc)]
nestedIdx :: [([String], PULoc)]
missingIdx :: [([String], PULoc)]
..}
where
F.Analysis { bBlocks :: forall a. Analysis a -> Maybe (BBGr (Analysis a))
F.bBlocks = Just BBGr (Analysis a)
gr } = ProgramUnit (Analysis a) -> Analysis a
forall a. ProgramUnit a -> a
forall (f :: * -> *) a. Annotated f => f a -> a
F.getAnnotation ProgramUnit (Analysis a)
pu
bedges :: BackEdgeMap
bedges = DomMap -> Gr (BB (Analysis a)) () -> BackEdgeMap
forall (gr :: * -> * -> *) a b.
Graph gr =>
DomMap -> gr a b -> BackEdgeMap
F.genBackEdgeMap (BBGr (Analysis a) -> DomMap
forall a. BBGr a -> DomMap
F.dominators BBGr (Analysis a)
gr) (Gr (BB (Analysis a)) () -> BackEdgeMap)
-> Gr (BB (Analysis a)) () -> BackEdgeMap
forall a b. (a -> b) -> a -> b
$ BBGr (Analysis a) -> Gr (BB (Analysis a)) ()
forall a. BBGr a -> Gr (BB a) ()
F.bbgrGr BBGr (Analysis a)
gr
ivmap :: InductionVarMapByASTBlock
ivmap = BackEdgeMap -> BBGr (Analysis a) -> InductionVarMapByASTBlock
forall a.
Data a =>
BackEdgeMap -> BBGr (Analysis a) -> InductionVarMapByASTBlock
F.genInductionVarMapByASTBlock BackEdgeMap
bedges BBGr (Analysis a)
gr
rdmap :: InOutMap ASTBlockNodeSet
rdmap = DefMap -> BBGr (Analysis a) -> InOutMap ASTBlockNodeSet
forall a.
Data a =>
DefMap -> BBGr (Analysis a) -> InOutMap ASTBlockNodeSet
F.reachingDefinitions DefMap
dm BBGr (Analysis a)
gr
flTo :: FlowsGraph a
flTo = BlockMap a
-> DefMap
-> BBGr (Analysis a)
-> InOutMap ASTBlockNodeSet
-> FlowsGraph a
forall a.
Data a =>
BlockMap a
-> DefMap
-> BBGr (Analysis a)
-> InOutMap ASTBlockNodeSet
-> FlowsGraph a
F.genFlowsToGraph BlockMap a
bm DefMap
dm BBGr (Analysis a)
gr InOutMap ASTBlockNodeSet
rdmap
flFrom :: FlowsGraph a
flFrom = FlowsGraph a -> FlowsGraph a
forall (gr :: * -> * -> *) a b. DynGraph gr => gr a b -> gr a b
grev FlowsGraph a
flTo
blocks :: [F.Block (F.Analysis a)]
blocks :: BB (Analysis a)
blocks = ProgramUnit (Analysis a) -> BB (Analysis a)
forall a. ProgramUnit a -> [Block a]
F.programUnitBody ProgramUnit (Analysis a)
pu
nestedIdx :: [([String], PULoc)]
nestedIdx = [ ([String]
ivars, (ProgramUnit (Analysis a) -> ProgramUnitName
forall a. Named a => a -> ProgramUnitName
F.getName ProgramUnit (Analysis a)
pu, String -> SrcSpan -> Origin
forall a. Spanned a => String -> a -> Origin
atSpannedInFile String
file SrcSpan
ss)) | ([String]
ivars, SrcSpan
ss) <- [String] -> BB (Analysis a) -> [([String], SrcSpan)]
getNestedIdx [] BB (Analysis a)
blocks ]
getNestedIdx :: [F.Name] -> [F.Block (F.Analysis a)] -> [([String], F.SrcSpan)]
getNestedIdx :: [String] -> BB (Analysis a) -> [([String], SrcSpan)]
getNestedIdx [String]
_ [] = []
getNestedIdx [String]
vs (b :: Block (Analysis a)
b@(F.BlDo Analysis a
_ SrcSpan
_ Maybe (Expression (Analysis a))
_ Maybe String
_ Maybe (Expression (Analysis a))
_ Maybe (DoSpecification (Analysis a))
_ BB (Analysis a)
body Maybe (Expression (Analysis a))
_):BB (Analysis a)
bs)
| String
v:[String]
_ <- Block (Analysis a) -> [String]
forall a. Data a => Block (Analysis a) -> [String]
F.blockVarDefs Block (Analysis a)
b = [String] -> BB (Analysis a) -> [([String], SrcSpan)]
getNestedIdx (String
vString -> [String] -> [String]
forall a. a -> [a] -> [a]
:[String]
vs) BB (Analysis a)
body [([String], SrcSpan)]
-> [([String], SrcSpan)] -> [([String], SrcSpan)]
forall a. [a] -> [a] -> [a]
++ [String] -> BB (Analysis a) -> [([String], SrcSpan)]
getNestedIdx [String]
vs BB (Analysis a)
bs
| Bool
otherwise = [String] -> BB (Analysis a) -> [([String], SrcSpan)]
getNestedIdx [String]
vs BB (Analysis a)
bs
getNestedIdx [String]
vs (Block (Analysis a)
b:BB (Analysis a)
bs) = [([String], SrcSpan)]
bad [([String], SrcSpan)]
-> [([String], SrcSpan)] -> [([String], SrcSpan)]
forall a. [a] -> [a] -> [a]
++ [String] -> BB (Analysis a) -> [([String], SrcSpan)]
getNestedIdx [String]
vs BB (Analysis a)
bs
where
vset :: Set String
vset = [String] -> Set String
forall a. Ord a => [a] -> Set a
S.fromList [String]
vs
vmap :: [(String, Int)]
vmap = [String] -> [Int] -> [(String, Int)]
forall a b. [a] -> [b] -> [(a, b)]
zip [String]
vs ([Int
0..] :: [Int])
subs :: [([(String, String)], SrcSpan)]
subs = [ ([(String, String)]
ivars, SrcSpan
ss)
| F.ExpSubscript Analysis a
_ SrcSpan
ss Expression (Analysis a)
_ (F.AList Analysis a
_ SrcSpan
_ [Index (Analysis a)]
is) <- Block (Analysis a) -> [Expression (Analysis a)]
forall from to. Biplate from to => from -> [to]
universeBi Block (Analysis a)
b :: [F.Expression (F.Analysis a)]
, let ivars :: [(String, String)]
ivars = [ (Expression (Analysis a) -> String
forall a. Expression (Analysis a) -> String
F.varName Expression (Analysis a)
e, Expression (Analysis a) -> String
forall a. Expression (Analysis a) -> String
F.srcName Expression (Analysis a)
e)
| Index (Analysis a)
i <- [Index (Analysis a)]
is
, e :: Expression (Analysis a)
e@(F.ExpValue Analysis a
_ SrcSpan
_ F.ValVariable{}) <- Index (Analysis a) -> [Expression (Analysis a)]
forall from to. Biplate from to => from -> [to]
universeBi Index (Analysis a)
i :: [F.Expression (F.Analysis a)]
, Expression (Analysis a) -> String
forall a. Expression (Analysis a) -> String
F.varName Expression (Analysis a)
e String -> Set String -> Bool
forall a. Ord a => a -> Set a -> Bool
`S.member` Set String
vset ] ]
bad :: [([String], SrcSpan)]
bad = [ (((String, String) -> String) -> [(String, String)] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (String, String) -> String
forall a b. (a, b) -> b
snd [(String, String)]
ivars, SrcSpan
ss)
| ([(String, String)]
ivars, SrcSpan
ss) <- [([(String, String)], SrcSpan)]
subs, let nums :: [Int]
nums = ((String, String) -> Maybe Int) -> [(String, String)] -> [Int]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe ((String -> [(String, Int)] -> Maybe Int)
-> [(String, Int)] -> String -> Maybe Int
forall a b c. (a -> b -> c) -> b -> a -> c
flip String -> [(String, Int)] -> Maybe Int
forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup [(String, Int)]
vmap (String -> Maybe Int)
-> ((String, String) -> String) -> (String, String) -> Maybe Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (String, String) -> String
forall a b. (a, b) -> a
fst) [(String, String)]
ivars, [Int]
nums [Int] -> [Int] -> Bool
forall a. Eq a => a -> a -> Bool
/= [Int] -> [Int]
forall a. Ord a => [a] -> [a]
sort [Int]
nums ]
missingIdx :: [([String], PULoc)]
missingIdx = [ ([String]
missing, (ProgramUnit (Analysis a) -> ProgramUnitName
forall a. Named a => a -> ProgramUnitName
F.getName ProgramUnit (Analysis a)
pu, String -> SrcSpan -> Origin
forall a. Spanned a => String -> a -> Origin
atSpannedInFile String
file SrcSpan
ss)) | Block (Analysis a)
b <- BB (Analysis a)
blocks
, ([String]
missing, SrcSpan
ss) <- [String] -> Block (Analysis a) -> [([String], SrcSpan)]
forall a'.
Data a' =>
[String] -> Block (Analysis a') -> [([String], SrcSpan)]
getMissingUse [] Block (Analysis a)
b ]
getMissingUse :: forall a'. Data a' => [String] -> F.Block (F.Analysis a') -> [([String], F.SrcSpan)]
getMissingUse :: forall a'.
Data a' =>
[String] -> Block (Analysis a') -> [([String], SrcSpan)]
getMissingUse [String]
excls (F.BlDo Analysis a'
_ SrcSpan
_ Maybe (Expression (Analysis a'))
_ Maybe String
_ Maybe (Expression (Analysis a'))
_ Maybe (DoSpecification (Analysis a'))
_ [Block (Analysis a')]
bs Maybe (Expression (Analysis a'))
_) = (Block (Analysis a') -> [([String], SrcSpan)])
-> [Block (Analysis a')] -> [([String], SrcSpan)]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap ([String] -> Block (Analysis a') -> [([String], SrcSpan)]
forall a'.
Data a' =>
[String] -> Block (Analysis a') -> [([String], SrcSpan)]
getMissingUse [String]
excls) [Block (Analysis a')]
bs
getMissingUse [String]
excls (F.BlDoWhile Analysis a'
_ SrcSpan
_ Maybe (Expression (Analysis a'))
_ Maybe String
_ Maybe (Expression (Analysis a'))
_ Expression (Analysis a')
_ [Block (Analysis a')]
bs Maybe (Expression (Analysis a'))
_) = (Block (Analysis a') -> [([String], SrcSpan)])
-> [Block (Analysis a')] -> [([String], SrcSpan)]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap ([String] -> Block (Analysis a') -> [([String], SrcSpan)]
forall a'.
Data a' =>
[String] -> Block (Analysis a') -> [([String], SrcSpan)]
getMissingUse [String]
excls) [Block (Analysis a')]
bs
getMissingUse [String]
excls (F.BlForall Analysis a'
_ SrcSpan
_ Maybe (Expression (Analysis a'))
_ Maybe String
_ ForallHeader (Analysis a')
_ [Block (Analysis a')]
bs Maybe (Expression (Analysis a'))
_) = (Block (Analysis a') -> [([String], SrcSpan)])
-> [Block (Analysis a')] -> [([String], SrcSpan)]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap ([String] -> Block (Analysis a') -> [([String], SrcSpan)]
forall a'.
Data a' =>
[String] -> Block (Analysis a') -> [([String], SrcSpan)]
getMissingUse [String]
excls) [Block (Analysis a')]
bs
getMissingUse [String]
excls b :: Block (Analysis a')
b@(F.BlIf F.Analysis{insLabel :: forall a. Analysis a -> Maybe Int
F.insLabel = Just Int
i} SrcSpan
_ss Maybe (Expression (Analysis a'))
_l Maybe String
_nm NonEmpty (Expression (Analysis a'), [Block (Analysis a')])
clauses Maybe [Block (Analysis a')]
mBlockElse Maybe (Expression (Analysis a'))
_ml)
| (Expression (Analysis a') -> Bool)
-> [Expression (Analysis a')] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (Int -> Int -> Expression (Analysis a') -> Bool
forall a' (b' :: * -> *).
(Data a', Data (b' (Analysis a'))) =>
Int -> Int -> b' (Analysis a') -> Bool
eligible Int
i ([String] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [String]
excls)) [Expression (Analysis a')]
conds = [([String], SrcSpan)]
bads [([String], SrcSpan)]
-> [([String], SrcSpan)] -> [([String], SrcSpan)]
forall a. [a] -> [a] -> [a]
++ [([String], SrcSpan)]
rest
| Bool
otherwise = [([String], SrcSpan)]
rest
where
clauses' :: [(Expression (Analysis a'), [Block (Analysis a')])]
clauses' = NonEmpty (Expression (Analysis a'), [Block (Analysis a')])
-> [(Expression (Analysis a'), [Block (Analysis a')])]
forall a. NonEmpty a -> [a]
NE.toList NonEmpty (Expression (Analysis a'), [Block (Analysis a')])
clauses
conds :: [Expression (Analysis a')]
conds = ((Expression (Analysis a'), [Block (Analysis a')])
-> Expression (Analysis a'))
-> [(Expression (Analysis a'), [Block (Analysis a')])]
-> [Expression (Analysis a')]
forall a b. (a -> b) -> [a] -> [b]
map (Expression (Analysis a'), [Block (Analysis a')])
-> Expression (Analysis a')
forall a b. (a, b) -> a
fst [(Expression (Analysis a'), [Block (Analysis a')])]
clauses'
blocks :: [[Block (Analysis a')]]
blocks = Maybe [Block (Analysis a')]
-> [[Block (Analysis a')]] -> [[Block (Analysis a')]]
forall a. Maybe a -> [a] -> [a]
mcons Maybe [Block (Analysis a')]
mBlockElse ([[Block (Analysis a')]] -> [[Block (Analysis a')]])
-> [[Block (Analysis a')]] -> [[Block (Analysis a')]]
forall a b. (a -> b) -> a -> b
$ ((Expression (Analysis a'), [Block (Analysis a')])
-> [Block (Analysis a')])
-> [(Expression (Analysis a'), [Block (Analysis a')])]
-> [[Block (Analysis a')]]
forall a b. (a -> b) -> [a] -> [b]
map (Expression (Analysis a'), [Block (Analysis a')])
-> [Block (Analysis a')]
forall a b. (a, b) -> b
snd [(Expression (Analysis a'), [Block (Analysis a')])]
clauses'
excl' :: [String]
excl' = Block (Analysis a') -> [String]
forall {f :: * -> *} {a}. Annotated f => f (Analysis a) -> [String]
getExcludes Block (Analysis a')
b
rest :: [([String], SrcSpan)]
rest = (Block (Analysis a') -> [([String], SrcSpan)])
-> [Block (Analysis a')] -> [([String], SrcSpan)]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap ([String] -> Block (Analysis a') -> [([String], SrcSpan)]
forall a'.
Data a' =>
[String] -> Block (Analysis a') -> [([String], SrcSpan)]
getMissingUse ([String]
excls [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ [String]
excl')) ([Block (Analysis a')] -> [([String], SrcSpan)])
-> [Block (Analysis a')] -> [([String], SrcSpan)]
forall a b. (a -> b) -> a -> b
$ [[Block (Analysis a')]] -> [Block (Analysis a')]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [[Block (Analysis a')]]
blocks
bads :: [([String], SrcSpan)]
bads = [String] -> Block (Analysis a') -> [([String], SrcSpan)]
forall a'.
Data a' =>
[String] -> Block (Analysis a') -> [([String], SrcSpan)]
getMissingUse' [String]
excls Block (Analysis a')
b
getMissingUse [String]
excls b :: Block (Analysis a')
b@(F.BlCase F.Analysis{insLabel :: forall a. Analysis a -> Maybe Int
F.insLabel = Just Int
i} SrcSpan
_ Maybe (Expression (Analysis a'))
_ Maybe String
_ Expression (Analysis a')
e [(AList Index (Analysis a'), [Block (Analysis a')])]
_ Maybe [Block (Analysis a')]
bss Maybe (Expression (Analysis a'))
_)
| Int -> Int -> Expression (Analysis a') -> Bool
forall a' (b' :: * -> *).
(Data a', Data (b' (Analysis a'))) =>
Int -> Int -> b' (Analysis a') -> Bool
eligible Int
i ([String] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [String]
excls) Expression (Analysis a')
e = [([String], SrcSpan)]
bads [([String], SrcSpan)]
-> [([String], SrcSpan)] -> [([String], SrcSpan)]
forall a. [a] -> [a] -> [a]
++ [([String], SrcSpan)]
rest
| Bool
otherwise = [([String], SrcSpan)]
rest
where
rest :: [([String], SrcSpan)]
rest = (Block (Analysis a') -> [([String], SrcSpan)])
-> [Block (Analysis a')] -> [([String], SrcSpan)]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap ([String] -> Block (Analysis a') -> [([String], SrcSpan)]
forall a'.
Data a' =>
[String] -> Block (Analysis a') -> [([String], SrcSpan)]
getMissingUse ([String]
excls [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ Block (Analysis a') -> [String]
forall {f :: * -> *} {a}. Annotated f => f (Analysis a) -> [String]
getExcludes Block (Analysis a')
b)) ([Block (Analysis a')] -> [([String], SrcSpan)])
-> [Block (Analysis a')] -> [([String], SrcSpan)]
forall a b. (a -> b) -> a -> b
$ Maybe [Block (Analysis a')] -> [Block (Analysis a')]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat Maybe [Block (Analysis a')]
bss
bads :: [([String], SrcSpan)]
bads = (([String], SrcSpan) -> ([String], SrcSpan))
-> [([String], SrcSpan)] -> [([String], SrcSpan)]
forall a b. (a -> b) -> [a] -> [b]
map ((SrcSpan -> SrcSpan) -> ([String], SrcSpan) -> ([String], SrcSpan)
forall a b. (a -> b) -> ([String], a) -> ([String], b)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (SrcSpan -> SrcSpan -> SrcSpan
forall a b. a -> b -> a
const (Expression (Analysis a') -> SrcSpan
forall a. Spanned a => a -> SrcSpan
F.getSpan Expression (Analysis a')
e))) ([([String], SrcSpan)] -> [([String], SrcSpan)])
-> [([String], SrcSpan)] -> [([String], SrcSpan)]
forall a b. (a -> b) -> a -> b
$ [String] -> Block (Analysis a') -> [([String], SrcSpan)]
forall a'.
Data a' =>
[String] -> Block (Analysis a') -> [([String], SrcSpan)]
getMissingUse' [String]
excls Block (Analysis a')
b
getMissingUse [String]
excls b :: Block (Analysis a')
b@(F.BlStatement F.Analysis{insLabel :: forall a. Analysis a -> Maybe Int
F.insLabel = Just Int
i} SrcSpan
_ Maybe (Expression (Analysis a'))
_ Statement (Analysis a')
st)
| Int -> Int -> Statement (Analysis a') -> Bool
forall a' (b' :: * -> *).
(Data a', Data (b' (Analysis a'))) =>
Int -> Int -> b' (Analysis a') -> Bool
eligible Int
i ([String] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [String]
excls) Statement (Analysis a')
st = [String] -> Block (Analysis a') -> [([String], SrcSpan)]
forall a'.
Data a' =>
[String] -> Block (Analysis a') -> [([String], SrcSpan)]
getMissingUse' [String]
excls Block (Analysis a')
b
| Bool
otherwise = []
getMissingUse [String]
_ F.BlInterface{} = []
getMissingUse [String]
_ F.BlComment{} = []
getMissingUse [String]
_ Block (Analysis a')
b = String -> [([String], SrcSpan)]
forall a. HasCallStack => String -> a
error (String -> [([String], SrcSpan)])
-> String -> [([String], SrcSpan)]
forall a b. (a -> b) -> a -> b
$ String
"checkArrayUse: getMissingUse: missing insLabel: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Block (Maybe Int) -> String
forall a. Show a => a -> String
show ((Analysis a' -> Maybe Int)
-> Block (Analysis a') -> Block (Maybe Int)
forall a b. (a -> b) -> Block a -> Block b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Analysis a' -> Maybe Int
forall a. Analysis a -> Maybe Int
F.insLabel Block (Analysis a')
b)
getMissingUse' :: forall a'. Data a' => [F.Name] -> F.Block (F.Analysis a') -> [([F.Name], F.SrcSpan)]
getMissingUse' :: forall a'.
Data a' =>
[String] -> Block (Analysis a') -> [([String], SrcSpan)]
getMissingUse' [String]
excls Block (Analysis a')
b
| Just Int
i <- Analysis a' -> Maybe Int
forall a. Analysis a -> Maybe Int
F.insLabel (Block (Analysis a') -> Analysis a'
forall a. Block a -> a
forall (f :: * -> *) a. Annotated f => f a -> a
F.getAnnotation Block (Analysis a')
b)
, Just Set String
ivarSet <- Int -> InductionVarMapByASTBlock -> Maybe (Set String)
forall a. Int -> IntMap a -> Maybe a
IM.lookup Int
i InductionVarMapByASTBlock
ivmap
, [Int]
flFroms <- Int -> [Int] -> [Int]
forall a. Int -> [a] -> [a]
drop Int
1 ([Int] -> [Int]) -> [Int] -> [Int]
forall a b. (a -> b) -> a -> b
$ Int -> FlowsGraph a -> [Int]
forall (gr :: * -> * -> *) a b. Graph gr => Int -> gr a b -> [Int]
bfs Int
i FlowsGraph a
flFrom
, Just BB (Analysis a)
flFromBlocks <- [Maybe (Block (Analysis a))] -> Maybe (BB (Analysis a))
forall (t :: * -> *) (m :: * -> *) a.
(Traversable t, Monad m) =>
t (m a) -> m (t a)
forall (m :: * -> *) a. Monad m => [m a] -> m [a]
sequence ([Maybe (Block (Analysis a))] -> Maybe (BB (Analysis a)))
-> [Maybe (Block (Analysis a))] -> Maybe (BB (Analysis a))
forall a b. (a -> b) -> a -> b
$ (Int -> Maybe (Block (Analysis a)))
-> [Int] -> [Maybe (Block (Analysis a))]
forall a b. (a -> b) -> [a] -> [b]
map ((Int -> BlockMap a -> Maybe (Block (Analysis a)))
-> BlockMap a -> Int -> Maybe (Block (Analysis a))
forall a b c. (a -> b -> c) -> b -> a -> c
flip Int -> BlockMap a -> Maybe (Block (Analysis a))
forall a. Int -> IntMap a -> Maybe a
IM.lookup BlockMap a
bm) [Int]
flFroms
, Set String
flFromBlockDefSet <- [String] -> Set String
forall a. Ord a => [a] -> Set a
S.fromList ([String] -> Set String) -> [String] -> Set String
forall a b. (a -> b) -> a -> b
$ (Block (Analysis a) -> [String]) -> BB (Analysis a) -> [String]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap Block (Analysis a) -> [String]
forall a. Data a => Block (Analysis a) -> [String]
F.blockVarDefs BB (Analysis a)
flFromBlocks
, Set String
missingIVars <- Set String
ivarSet Set String -> Set String -> Set String
forall a. Ord a => Set a -> Set a -> Set a
`S.difference` [String] -> Set String
forall a. Ord a => [a] -> Set a
S.fromList [String]
excls Set String -> Set String -> Set String
forall a. Ord a => Set a -> Set a -> Set a
`S.difference` Set String
flFromBlockDefSet
, Set String
missingIVars' <- (String -> String) -> Set String -> Set String
forall b a. Ord b => (a -> b) -> Set a -> Set b
S.map (\ String
v -> String
"unk" String -> Maybe String -> String
forall a. a -> Maybe a -> a
`fromMaybe` String -> Maybe String
findSrcNameInDefMap String
v) Set String
missingIVars
, Bool -> Bool
not (Set String -> Bool
forall a. Set a -> Bool
S.null Set String
missingIVars) = [(Set String -> [String]
forall a. Set a -> [a]
S.toList Set String
missingIVars', Block (Analysis a') -> SrcSpan
forall a. Spanned a => a -> SrcSpan
F.getSpan Block (Analysis a')
b)]
getMissingUse' [String]
_ Block (Analysis a')
_ = []
eligible :: forall a' b'. (Data a', Data (b' (F.Analysis a'))) => Int -> Int -> b' (F.Analysis a') -> Bool
eligible :: forall a' (b' :: * -> *).
(Data a', Data (b' (Analysis a'))) =>
Int -> Int -> b' (Analysis a') -> Bool
eligible Int
i Int
numExcls b' (Analysis a')
x
| Just Set String
ivars <- Int -> InductionVarMapByASTBlock -> Maybe (Set String)
forall a. Int -> IntMap a -> Maybe a
IM.lookup Int
i InductionVarMapByASTBlock
ivmap =
Bool -> Bool
not (Bool -> Bool) -> Bool -> Bool
forall a b. (a -> b) -> a -> b
$ [()] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [ () | F.ExpSubscript Analysis a'
_ SrcSpan
_ Expression (Analysis a')
_ (F.AList Analysis a'
_ SrcSpan
_ [Index (Analysis a')]
idxs) <- b' (Analysis a') -> [Expression (Analysis a')]
forall from to. Biplate from to => from -> [to]
universeBi b' (Analysis a')
x :: [F.Expression (F.Analysis a')]
, [Index (Analysis a')] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Index (Analysis a')]
idxs Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Set String -> Int
forall a. Set a -> Int
S.size Set String
ivars Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
numExcls ]
| Bool
otherwise = Bool
False
getExcludes :: f (Analysis a) -> [String]
getExcludes f (Analysis a)
b
| Just Int
i <- Analysis a -> Maybe Int
forall a. Analysis a -> Maybe Int
F.insLabel (f (Analysis a) -> Analysis a
forall a. f a -> a
forall (f :: * -> *) a. Annotated f => f a -> a
F.getAnnotation f (Analysis a)
b)
, Just Set String
ivarSet <- Int -> InductionVarMapByASTBlock -> Maybe (Set String)
forall a. Int -> IntMap a -> Maybe a
IM.lookup Int
i InductionVarMapByASTBlock
ivmap
, [Int]
flFroms <- Int -> [Int] -> [Int]
forall a. Int -> [a] -> [a]
drop Int
1 ([Int] -> [Int]) -> [Int] -> [Int]
forall a b. (a -> b) -> a -> b
$ Int -> FlowsGraph a -> [Int]
forall (gr :: * -> * -> *) a b. Graph gr => Int -> gr a b -> [Int]
bfs Int
i FlowsGraph a
flFrom
, Just BB (Analysis a)
flFromBlocks <- [Maybe (Block (Analysis a))] -> Maybe (BB (Analysis a))
forall (t :: * -> *) (m :: * -> *) a.
(Traversable t, Monad m) =>
t (m a) -> m (t a)
forall (m :: * -> *) a. Monad m => [m a] -> m [a]
sequence ([Maybe (Block (Analysis a))] -> Maybe (BB (Analysis a)))
-> [Maybe (Block (Analysis a))] -> Maybe (BB (Analysis a))
forall a b. (a -> b) -> a -> b
$ (Int -> Maybe (Block (Analysis a)))
-> [Int] -> [Maybe (Block (Analysis a))]
forall a b. (a -> b) -> [a] -> [b]
map ((Int -> BlockMap a -> Maybe (Block (Analysis a)))
-> BlockMap a -> Int -> Maybe (Block (Analysis a))
forall a b c. (a -> b -> c) -> b -> a -> c
flip Int -> BlockMap a -> Maybe (Block (Analysis a))
forall a. Int -> IntMap a -> Maybe a
IM.lookup BlockMap a
bm) [Int]
flFroms
, Set String
flFromBlockDefSet <- [String] -> Set String
forall a. Ord a => [a] -> Set a
S.fromList ([String] -> Set String) -> [String] -> Set String
forall a b. (a -> b) -> a -> b
$ (Block (Analysis a) -> [String]) -> BB (Analysis a) -> [String]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap Block (Analysis a) -> [String]
forall a. Data a => Block (Analysis a) -> [String]
F.blockVarDefs BB (Analysis a)
flFromBlocks
= Set String -> [String]
forall a. Set a -> [a]
S.toList (Set String
ivarSet Set String -> Set String -> Set String
forall a. Ord a => Set a -> Set a -> Set a
`S.intersection` Set String
flFromBlockDefSet)
| Bool
otherwise = []
findSrcNameInDefMap :: String -> Maybe String
findSrcNameInDefMap String
v = do
ASTBlockNodeSet
defSet <- String -> DefMap -> Maybe ASTBlockNodeSet
forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup String
v DefMap
dm
BB (Analysis a)
bs <- (Int -> Maybe (Block (Analysis a)))
-> [Int] -> Maybe (BB (Analysis a))
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
mapM ((Int -> BlockMap a -> Maybe (Block (Analysis a)))
-> BlockMap a -> Int -> Maybe (Block (Analysis a))
forall a b c. (a -> b -> c) -> b -> a -> c
flip Int -> BlockMap a -> Maybe (Block (Analysis a))
forall a. Int -> IntMap a -> Maybe a
IM.lookup BlockMap a
bm) ([Int] -> Maybe (BB (Analysis a)))
-> [Int] -> Maybe (BB (Analysis a))
forall a b. (a -> b) -> a -> b
$ ASTBlockNodeSet -> [Int]
IS.toList ASTBlockNodeSet
defSet
[Maybe String] -> Maybe String
forall (t :: * -> *) (m :: * -> *) a.
(Foldable t, MonadPlus m) =>
t (m a) -> m a
msum ((Block (Analysis a) -> Maybe String)
-> BB (Analysis a) -> [Maybe String]
forall a b. (a -> b) -> [a] -> [b]
map (String -> Block (Analysis a) -> Maybe String
forall a. Data a => String -> Block (Analysis a) -> Maybe String
findSrcName String
v) BB (Analysis a)
bs)
checkPU ProgramUnit (Analysis a)
_ = CheckArrayReport
forall a. Monoid a => a
mempty
let reports :: [CheckArrayReport]
reports = (ProgramUnit (Analysis a) -> CheckArrayReport)
-> [ProgramUnit (Analysis a)] -> [CheckArrayReport]
forall a b. (a -> b) -> [a] -> [b]
map ProgramUnit (Analysis a) -> CheckArrayReport
checkPU (ProgramFile (Analysis a) -> [ProgramUnit (Analysis a)]
forall from to. Biplate from to => from -> [to]
universeBi ProgramFile (Analysis a)
pf'')
CheckArrayReport -> PureAnalysis String () CheckArrayReport
forall a. a -> AnalysisT String () Identity a
forall (m :: * -> *) a. Monad m => a -> m a
return (CheckArrayReport -> PureAnalysis String () CheckArrayReport)
-> CheckArrayReport -> PureAnalysis String () CheckArrayReport
forall a b. NFData a => (a -> b) -> a -> b
$!! [CheckArrayReport] -> CheckArrayReport
forall a. Monoid a => [a] -> a
mconcat [CheckArrayReport]
reports
mcons :: Maybe a -> [a] -> [a]
mcons :: forall a. Maybe a -> [a] -> [a]
mcons Maybe a
ma [a]
as = [a] -> (a -> [a]) -> Maybe a -> [a]
forall b a. b -> (a -> b) -> Maybe a -> b
maybe [a]
as (a -> [a] -> [a]
forall a. a -> [a] -> [a]
:[a]
as) Maybe a
ma
findSrcName :: forall a. Data a => F.Name -> F.Block (F.Analysis a) -> Maybe F.Name
findSrcName :: forall a. Data a => String -> Block (Analysis a) -> Maybe String
findSrcName String
v Block (Analysis a)
b = [String] -> Maybe String
forall a. [a] -> Maybe a
listToMaybe
[ Expression (Analysis a) -> String
forall a. Expression (Analysis a) -> String
F.srcName Expression (Analysis a)
e | e :: Expression (Analysis a)
e@(F.ExpValue Analysis a
_ SrcSpan
_ F.ValVariable{}) <- Block (Analysis a) -> [Expression (Analysis a)]
forall from to. Biplate from to => from -> [to]
universeBi Block (Analysis a)
b :: [F.Expression (F.Analysis a)]
, Expression (Analysis a) -> String
forall a. Expression (Analysis a) -> String
F.varName Expression (Analysis a)
e String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
v ]
instance Describe CheckArrayReport where
describeBuilder :: CheckArrayReport -> Builder
describeBuilder (CheckArrayReport {[([String], PULoc)]
nestedIdx :: CheckArrayReport -> [([String], PULoc)]
missingIdx :: CheckArrayReport -> [([String], PULoc)]
nestedIdx :: [([String], PULoc)]
missingIdx :: [([String], PULoc)]
..})
| [([String], PULoc)] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [([String], PULoc)]
nestedIdx Bool -> Bool -> Bool
&& [([String], PULoc)] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [([String], PULoc)]
missingIdx = Builder
"no cases detected"
| Bool
otherwise = Text -> Builder
Builder.fromText (Text -> Builder) -> ([Text] -> Text) -> [Text] -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Text] -> Text
unlines ([Text] -> Builder) -> [Text] -> Builder
forall a b. (a -> b) -> a -> b
$
[ Origin -> Text
forall a. Describe a => a -> Text
describe Origin
orig Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" possibly less efficient order of subscript indices: " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> [Text] -> Text
intercalate Text
", " ((String -> Text) -> [String] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
map String -> Text
forall a. Describe a => a -> Text
describe [String]
ivars)
| ([String]
ivars, (ProgramUnitName
_, Origin
orig)) <- [([String], PULoc)]
nestedIdx ] [Text] -> [Text] -> [Text]
forall a. [a] -> [a] -> [a]
++
[ Origin -> Text
forall a. Describe a => a -> Text
describe Origin
orig Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" possibly missing use of variable(s) in array subscript: " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> [Text] -> Text
intercalate Text
", " ((String -> Text) -> [String] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
map String -> Text
forall a. Describe a => a -> Text
describe [String]
ivars)
| ([String]
ivars, (ProgramUnitName
_, Origin
orig)) <- [([String], PULoc)]
missingIdx ]
instance ExitCodeOfReport CheckArrayReport where
exitCodeOf :: CheckArrayReport -> Int
exitCodeOf (CheckArrayReport {[([String], PULoc)]
nestedIdx :: CheckArrayReport -> [([String], PULoc)]
missingIdx :: CheckArrayReport -> [([String], PULoc)]
nestedIdx :: [([String], PULoc)]
missingIdx :: [([String], PULoc)]
..})
| [([String], PULoc)] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [([String], PULoc)]
nestedIdx = Int
0
| Bool
otherwise = Int
1