Return list of notes rather than a Map -> Map
This commit is contained in:
parent
05cb806642
commit
585529a636
|
@ -36,10 +36,11 @@ checks = concat [
|
||||||
,[checkShebang, checkUndeclaredBash]
|
,[checkShebang, checkUndeclaredBash]
|
||||||
]
|
]
|
||||||
|
|
||||||
runAllAnalytics = checkList checks
|
runAllAnalytics root m = addToMap (checkList checks root) m
|
||||||
checkList l t m = foldl (\x f -> f t x) m l
|
checkList l t = concatMap (\f -> f t) l
|
||||||
|
addToMap list map = foldr (\(id,note) m -> Map.adjust (\(Metadata pos notes) -> Metadata pos (note:notes)) id m) map list
|
||||||
|
|
||||||
runBasicAnalysis f t m = snd $ runState (doAnalysis f t) m
|
runBasicAnalysis f t = snd $ runState (doAnalysis f t) []
|
||||||
basicChecks = [
|
basicChecks = [
|
||||||
checkUuoc
|
checkUuoc
|
||||||
,checkPipePitfalls
|
,checkPipePitfalls
|
||||||
|
@ -85,14 +86,13 @@ treeChecks = [
|
||||||
,checkSingleQuotedVariables
|
,checkSingleQuotedVariables
|
||||||
]
|
]
|
||||||
|
|
||||||
runBasicTreeAnalysis checks token metaMap =
|
runBasicTreeAnalysis checks token =
|
||||||
checkList (map runTree checks) token metaMap
|
checkList (map runTree checks) token
|
||||||
where
|
where
|
||||||
parentTree = getParentTree token
|
parentTree = getParentTree token
|
||||||
runTree f t m = runBasicAnalysis (flip f $ parentTree) t m
|
runTree f t = runBasicAnalysis (flip f $ parentTree) t
|
||||||
|
|
||||||
modifyMap = modify
|
addNoteFor id note = modify ((id, note):)
|
||||||
addNoteFor id note = modifyMap $ Map.adjust (\(Metadata pos notes) -> Metadata pos (note:notes)) id
|
|
||||||
warn id note = addNoteFor id $ Note WarningC $ note
|
warn id note = addNoteFor id $ Note WarningC $ note
|
||||||
err id note = addNoteFor id $ Note ErrorC $ note
|
err id note = addNoteFor id $ Note ErrorC $ note
|
||||||
info id note = addNoteFor id $ Note InfoC $ note
|
info id note = addNoteFor id $ Note InfoC $ note
|
||||||
|
@ -143,7 +143,7 @@ verifyNotTree f s = checkTree f s == Just False
|
||||||
checkBasic f s = checkFull (runBasicAnalysis f) s
|
checkBasic f s = checkFull (runBasicAnalysis f) s
|
||||||
checkTree f s = checkFull (runBasicTreeAnalysis [f]) s
|
checkTree f s = checkFull (runBasicTreeAnalysis [f]) s
|
||||||
checkFull f s = case parseShell "-" s of
|
checkFull f s = case parseShell "-" s of
|
||||||
(ParseResult (Just (t, m)) _) -> Just . not $ (notesFromMap $ f t m) == (notesFromMap m)
|
(ParseResult (Just (t, m)) _) -> Just . not . null $ f t
|
||||||
_ -> Nothing
|
_ -> Nothing
|
||||||
|
|
||||||
|
|
||||||
|
@ -244,19 +244,19 @@ isMagicInQuotes _ = False
|
||||||
|
|
||||||
prop_checkShebang1 = verifyFull checkShebang "#!/usr/bin/env bash -x\necho cow"
|
prop_checkShebang1 = verifyFull checkShebang "#!/usr/bin/env bash -x\necho cow"
|
||||||
prop_checkShebang2 = verifyNotFull checkShebang "#! /bin/sh -l "
|
prop_checkShebang2 = verifyNotFull checkShebang "#! /bin/sh -l "
|
||||||
checkShebang (T_Script id sb _) m =
|
checkShebang (T_Script id sb _) =
|
||||||
if (length $ words sb) > 2 then
|
if (length $ words sb) > 2 then
|
||||||
let note = Note ErrorC $ "On most OS, shebangs can only specify a single parameter."
|
let note = Note ErrorC $ "On most OS, shebangs can only specify a single parameter."
|
||||||
in Map.adjust (\(Metadata pos notes) -> Metadata pos (note:notes)) id m
|
in [(id, note)]
|
||||||
else m
|
else []
|
||||||
|
|
||||||
prop_checkUndeclaredBash = verifyFull checkUndeclaredBash "#!/bin/sh -l\nwhile read a; do :; done < <(a)"
|
prop_checkUndeclaredBash = verifyFull checkUndeclaredBash "#!/bin/sh -l\nwhile read a; do :; done < <(a)"
|
||||||
prop_checkUndeclaredBash2 = verifyNotFull checkUndeclaredBash "#!/bin/bash\nwhile read a; do :; done < <(a)"
|
prop_checkUndeclaredBash2 = verifyNotFull checkUndeclaredBash "#!/bin/bash\nwhile read a; do :; done < <(a)"
|
||||||
checkUndeclaredBash t@(T_Script id sb _) m =
|
checkUndeclaredBash t@(T_Script id sb _) =
|
||||||
let tokens = words sb
|
let tokens = words sb
|
||||||
in if (not $ null tokens) && "/sh" `isSuffixOf` (head tokens)
|
in if (not $ null tokens) && "/sh" `isSuffixOf` (head tokens)
|
||||||
then runBasicAnalysis bashism t m
|
then runBasicAnalysis bashism t
|
||||||
else m
|
else []
|
||||||
where
|
where
|
||||||
errMsg id s = err id $ "The shebang specifies sh, so " ++ s ++ " is not supported, even if sh is bash."
|
errMsg id s = err id $ "The shebang specifies sh, so " ++ s ++ " is not supported, even if sh is bash."
|
||||||
warnMsg id s = warn id $ "The shebang specifies sh, so " ++ s ++ " may not be supported."
|
warnMsg id s = warn id $ "The shebang specifies sh, so " ++ s ++ " may not be supported."
|
||||||
|
@ -802,10 +802,10 @@ prop_subshellAssignmentCheck7 = verifyFull subshellAssignmentCheck "cmd | whi
|
||||||
prop_subshellAssignmentCheck8 = verifyFull subshellAssignmentCheck "n=3 & echo $((n++))"
|
prop_subshellAssignmentCheck8 = verifyFull subshellAssignmentCheck "n=3 & echo $((n++))"
|
||||||
prop_subshellAssignmentCheck9 = verifyFull subshellAssignmentCheck "read n & n=foo$n"
|
prop_subshellAssignmentCheck9 = verifyFull subshellAssignmentCheck "read n & n=foo$n"
|
||||||
prop_subshellAssignmentCheck10 = verifyFull subshellAssignmentCheck "(( n <<= 3 )) & (( n |= 4 )) &"
|
prop_subshellAssignmentCheck10 = verifyFull subshellAssignmentCheck "(( n <<= 3 )) & (( n |= 4 )) &"
|
||||||
subshellAssignmentCheck t map =
|
subshellAssignmentCheck t =
|
||||||
let flow = getVariableFlow t
|
let flow = getVariableFlow t
|
||||||
check = findSubshelled flow [("oops",[])] Map.empty
|
check = findSubshelled flow [("oops",[])] Map.empty
|
||||||
in snd $ runState check map
|
in snd $ runState check []
|
||||||
|
|
||||||
|
|
||||||
data Scope = SubshellScope String | NoneScope deriving (Show, Eq)
|
data Scope = SubshellScope String | NoneScope deriving (Show, Eq)
|
||||||
|
@ -911,7 +911,7 @@ getVariableFlow t =
|
||||||
mapM_ (\v -> modify ((Reference v):)) read
|
mapM_ (\v -> modify ((Reference v):)) read
|
||||||
mapM_ (\v -> modify ((Assignment v):)) written
|
mapM_ (\v -> modify ((Assignment v):)) written
|
||||||
|
|
||||||
findSubshelled :: [StackData] -> [(String, [(Id,String)])] -> (Map.Map String VariableState) -> State (Map.Map Id Metadata) ()
|
findSubshelled :: [StackData] -> [(String, [(Id,String)])] -> (Map.Map String VariableState) -> State [(Id, Note)] ()
|
||||||
findSubshelled [] _ _ = return ()
|
findSubshelled [] _ _ = return ()
|
||||||
findSubshelled ((Assignment x@(id, str)):rest) ((reason,scope):lol) deadVars =
|
findSubshelled ((Assignment x@(id, str)):rest) ((reason,scope):lol) deadVars =
|
||||||
findSubshelled rest ((reason, x:scope):lol) $ Map.insert str Alive deadVars
|
findSubshelled rest ((reason, x:scope):lol) $ Map.insert str Alive deadVars
|
||||||
|
@ -947,22 +947,22 @@ prop_checkSpacefulnessC = verifyNotFull checkSpacefulness "(( $1 + 3 ))"
|
||||||
prop_checkSpacefulnessD = verifyNotFull checkSpacefulness "if [[ $2 -gt 14 ]]; then true; fi"
|
prop_checkSpacefulnessD = verifyNotFull checkSpacefulness "if [[ $2 -gt 14 ]]; then true; fi"
|
||||||
prop_checkSpacefulnessE = verifyNotFull checkSpacefulness "foo=$3 env"
|
prop_checkSpacefulnessE = verifyNotFull checkSpacefulness "foo=$3 env"
|
||||||
|
|
||||||
checkSpacefulness t metaMap =
|
checkSpacefulness t =
|
||||||
let (_, (newMetaMap, spaceMap)) = runState (doStackAnalysis startScope endScope t) (metaMap, Map.empty)
|
let (_, (newMetaMap, spaceMap)) = runState (doStackAnalysis startScope endScope t) ([], Map.empty)
|
||||||
in newMetaMap
|
in newMetaMap
|
||||||
where
|
where
|
||||||
isSpaceless m s = (not $ all isDigit s) && (Map.findWithDefault Spaceless s m) == Spaceless
|
isSpaceless m s = (not $ all isDigit s) && (Map.findWithDefault Spaceless s m) == Spaceless
|
||||||
addInfo :: (Id, String) -> State (Map.Map Id Metadata, Map.Map String VariableType) ()
|
addInfo :: (Id, String) -> State ([(Id,Note)], Map.Map String VariableType) ()
|
||||||
addInfo (id, s) = do
|
addInfo (id, s) = do
|
||||||
(metaMap, spaceMap) <- get
|
(list, spaceMap) <- get
|
||||||
when (not (inUnquotableContext parents (Map.findWithDefault undefined id items)) && not (isSpaceless spaceMap s)) $ do
|
when (not (inUnquotableContext parents (Map.findWithDefault undefined id items)) && not (isSpaceless spaceMap s)) $ do
|
||||||
let note = Note InfoC "This variable may contain spaces/globs. Quote it unless you want splitting."
|
let note = Note InfoC "This variable may contain spaces/globs. Quote it unless you want splitting."
|
||||||
let mm = Map.adjust (\(Metadata pos notes) -> Metadata pos (note:notes)) id metaMap
|
let newlist = (id, note):list
|
||||||
put (mm, spaceMap)
|
put (newlist, spaceMap)
|
||||||
|
|
||||||
registerSpacing (id, s, typ) = do
|
registerSpacing (id, s, typ) = do
|
||||||
(metaMap, spaceMap) <- get
|
(list, spaceMap) <- get
|
||||||
put (metaMap, Map.insert s typ spaceMap)
|
put (list, Map.insert s typ spaceMap)
|
||||||
|
|
||||||
parents = getParentTree t
|
parents = getParentTree t
|
||||||
items = getTokenMap t
|
items = getTokenMap t
|
||||||
|
|
Loading…
Reference in New Issue