Return list of notes rather than a Map -> Map

This commit is contained in:
Vidar Holen 2013-02-11 19:26:40 -08:00
parent 05cb806642
commit 585529a636
1 changed files with 26 additions and 26 deletions

View File

@ -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