mirror of
https://github.com/koalaman/shellcheck
synced 2025-07-07 05:21:34 -07:00
Control Flow Graph / Data Flow Analysis support
This commit is contained in:
parent
7946bf5657
commit
f77a545282
17 changed files with 2909 additions and 135 deletions
101
src/ShellCheck/Checks/ControlFlow.hs
Normal file
101
src/ShellCheck/Checks/ControlFlow.hs
Normal file
|
@ -0,0 +1,101 @@
|
|||
{-
|
||||
Copyright 2022 Vidar Holen
|
||||
|
||||
This file is part of ShellCheck.
|
||||
https://www.shellcheck.net
|
||||
|
||||
ShellCheck is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
ShellCheck is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
-}
|
||||
{-# LANGUAGE TemplateHaskell #-}
|
||||
|
||||
-- Checks that run on the Control Flow Graph (as opposed to the AST)
|
||||
-- This is scaffolding for a work in progress.
|
||||
|
||||
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 = []
|
||||
|
||||
-- A check that runs on the entire graph
|
||||
type ControlFlowCheck = Analysis
|
||||
-- A check invoked once per node, with its (pre,post) data
|
||||
type ControlFlowNodeCheck = LNode CFNode -> (ProgramState, ProgramState) -> Analysis
|
||||
-- A check invoked once per effect, with its node's (pre,post) data
|
||||
type ControlFlowEffectCheck = IdTagged CFEffect -> Node -> (ProgramState, ProgramState) -> Analysis
|
||||
|
||||
|
||||
checker :: AnalysisSpec -> Parameters -> Checker
|
||||
checker spec params = Checker {
|
||||
perScript = const $ sequence_ controlFlowChecks,
|
||||
perToken = const $ return ()
|
||||
}
|
||||
|
||||
controlFlowChecks :: [ControlFlowCheck]
|
||||
controlFlowChecks = [
|
||||
runNodeChecks controlFlowNodeChecks
|
||||
]
|
||||
|
||||
controlFlowNodeChecks :: [ControlFlowNodeCheck]
|
||||
controlFlowNodeChecks = [
|
||||
runEffectChecks controlFlowEffectChecks
|
||||
]
|
||||
|
||||
controlFlowEffectChecks :: [ControlFlowEffectCheck]
|
||||
controlFlowEffectChecks = [
|
||||
]
|
||||
|
||||
runNodeChecks :: [ControlFlowNodeCheck] -> ControlFlowCheck
|
||||
runNodeChecks perNode = do
|
||||
cfg <- asks cfgAnalysis
|
||||
runOnAll cfg
|
||||
where
|
||||
getData datas n@(node, label) = do
|
||||
(pre, post) <- M.lookup node datas
|
||||
return (n, (pre, post))
|
||||
|
||||
runOn :: (LNode CFNode, (ProgramState, ProgramState)) -> Analysis
|
||||
runOn (node, prepost) = mapM_ (\c -> c node prepost) perNode
|
||||
runOnAll cfg = mapM_ runOn $ mapMaybe (getData $ nodeToData cfg) $ labNodes (graph cfg)
|
||||
|
||||
runEffectChecks :: [ControlFlowEffectCheck] -> ControlFlowNodeCheck
|
||||
runEffectChecks list = checkNode
|
||||
where
|
||||
checkNode (node, label) prepost =
|
||||
case label of
|
||||
CFApplyEffects effects -> mapM_ (\effect -> mapM_ (\c -> c effect node prepost) list) effects
|
||||
_ -> return ()
|
||||
|
||||
|
||||
return []
|
||||
runTests = $( [| $(forAllProperties) (quickCheckWithResult (stdArgs { maxSuccess = 1 }) ) |])
|
Loading…
Add table
Add a link
Reference in a new issue