{-# LANGUAGE TemplateHaskell #-}
module ShellCheck.Checks.ControlFlow (checker, optionalChecks, ShellCheck.Checks.ControlFlow.runTests) where
import ShellCheck.AST
import ShellCheck.ASTLib
import ShellCheck.CFG hiding (cfgAnalysis)
import ShellCheck.CFGAnalysis
import ShellCheck.AnalyzerLib
import ShellCheck.Data
import ShellCheck.Interface
import Control.Monad
import Control.Monad.Reader
import Data.Graph.Inductive.Graph
import qualified Data.Map as M
import qualified Data.Set as S
import Data.List
import Data.Maybe
import Test.QuickCheck.All (forAllProperties)
import Test.QuickCheck.Test (quickCheckWithResult, stdArgs, maxSuccess)
optionalChecks :: [CheckDescription]
optionalChecks :: [CheckDescription]
optionalChecks = []
type ControlFlowCheck = Analysis
type ControlFlowNodeCheck = LNode CFNode -> (ProgramState, ProgramState) -> Analysis
type ControlFlowEffectCheck = IdTagged CFEffect -> Node -> (ProgramState, ProgramState) -> Analysis
checker :: AnalysisSpec -> Parameters -> Checker
checker :: AnalysisSpec -> Parameters -> Checker
checker AnalysisSpec
spec Parameters
params = Checker {
perScript :: Root -> Analysis
perScript = forall a b. a -> b -> a
const forall a b. (a -> b) -> a -> b
$ forall (t :: * -> *) (m :: * -> *) a.
(Foldable t, Monad m) =>
t (m a) -> m ()
sequence_ [Analysis]
controlFlowChecks,
perToken :: Token -> Analysis
perToken = forall a b. a -> b -> a
const forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a. Monad m => a -> m a
return ()
}
controlFlowChecks :: [ControlFlowCheck]
controlFlowChecks :: [Analysis]
controlFlowChecks = [
[ControlFlowNodeCheck] -> Analysis
runNodeChecks [ControlFlowNodeCheck]
controlFlowNodeChecks
]
controlFlowNodeChecks :: [ControlFlowNodeCheck]
controlFlowNodeChecks :: [ControlFlowNodeCheck]
controlFlowNodeChecks = [
[ControlFlowEffectCheck] -> ControlFlowNodeCheck
runEffectChecks [ControlFlowEffectCheck]
controlFlowEffectChecks
]
controlFlowEffectChecks :: [ControlFlowEffectCheck]
controlFlowEffectChecks :: [ControlFlowEffectCheck]
controlFlowEffectChecks = [
]
runNodeChecks :: [ControlFlowNodeCheck] -> ControlFlowCheck
runNodeChecks :: [ControlFlowNodeCheck] -> Analysis
runNodeChecks [ControlFlowNodeCheck]
perNode = do
CFGAnalysis
cfg <- forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks Parameters -> CFGAnalysis
cfgAnalysis
CFGAnalysis -> Analysis
runOnAll CFGAnalysis
cfg
where
getData :: Map k (a, b) -> (k, b) -> Maybe ((k, b), (a, b))
getData Map k (a, b)
datas n :: (k, b)
n@(k
node, b
label) = do
(a
pre, b
post) <- forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup k
node Map k (a, b)
datas
forall (m :: * -> *) a. Monad m => a -> m a
return ((k, b)
n, (a
pre, b
post))
runOn :: (LNode CFNode, (ProgramState, ProgramState)) -> Analysis
runOn :: (LNode CFNode, (ProgramState, ProgramState)) -> Analysis
runOn (LNode CFNode
node, (ProgramState, ProgramState)
prepost) = forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ (\ControlFlowNodeCheck
c -> ControlFlowNodeCheck
c LNode CFNode
node (ProgramState, ProgramState)
prepost) [ControlFlowNodeCheck]
perNode
runOnAll :: CFGAnalysis -> Analysis
runOnAll CFGAnalysis
cfg = forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ (LNode CFNode, (ProgramState, ProgramState)) -> Analysis
runOn forall a b. (a -> b) -> a -> b
$ forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe (forall {k} {a} {b} {b}.
Ord k =>
Map k (a, b) -> (k, b) -> Maybe ((k, b), (a, b))
getData forall a b. (a -> b) -> a -> b
$ CFGAnalysis -> Map Node (ProgramState, ProgramState)
nodeToData CFGAnalysis
cfg) forall a b. (a -> b) -> a -> b
$ forall (gr :: * -> * -> *) a b. Graph gr => gr a b -> [LNode a]
labNodes (CFGAnalysis -> CFGraph
graph CFGAnalysis
cfg)
runEffectChecks :: [ControlFlowEffectCheck] -> ControlFlowNodeCheck
runEffectChecks :: [ControlFlowEffectCheck] -> ControlFlowNodeCheck
runEffectChecks [ControlFlowEffectCheck]
list = ControlFlowNodeCheck
checkNode
where
checkNode :: ControlFlowNodeCheck
checkNode (Node
node, CFNode
label) (ProgramState, ProgramState)
prepost =
case CFNode
label of
CFApplyEffects [IdTagged CFEffect]
effects -> forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ (\IdTagged CFEffect
effect -> forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ (\ControlFlowEffectCheck
c -> ControlFlowEffectCheck
c IdTagged CFEffect
effect Node
node (ProgramState, ProgramState)
prepost) [ControlFlowEffectCheck]
list) [IdTagged CFEffect]
effects
CFNode
_ -> forall (m :: * -> *) a. Monad m => a -> m a
return ()
return []
runTests :: IO Bool
runTests = $( [| $(forAllProperties) (quickCheckWithResult (stdArgs { maxSuccess = 1 }) ) |])