Check PS1/PROMPT_COMMAND/trap for simple variable references

This commit is contained in:
Vidar Holen 2014-07-27 09:51:48 -07:00
parent 0347ce1b7a
commit dbadca9f61
1 changed files with 42 additions and 2 deletions

View File

@ -290,6 +290,15 @@ matches string regex = isJust $ matchRegex regex string
headOrDefault _ (a:_) = a headOrDefault _ (a:_) = a
headOrDefault def _ = def headOrDefault def _ = def
getAllMatches :: Regex -> String -> [[String]]
getAllMatches regex str = fromJust $ f str
where
f str = do
(_, _, rest, groups) <- matchRegexAll regex str
more <- f rest
return $ groups : more
`mappend` return []
isConstant token = isConstant token =
case token of case token of
T_NormalWord _ l -> all isConstant l T_NormalWord _ l -> all isConstant l
@ -1318,7 +1327,8 @@ isQuoteFree tree t =
T_Arithmetic {} -> return True T_Arithmetic {} -> return True
T_Assignment {} -> return True T_Assignment {} -> return True
T_Redirecting {} -> return $ T_Redirecting {} -> return $
any (isCommand t) ["local", "declare", "typeset", "export"] -- Not true, just a hack to prevent warning about non-expansion refs
any (isCommand t) ["local", "declare", "typeset", "export", "trap"]
T_DoubleQuoted _ _ -> return True T_DoubleQuoted _ _ -> return True
T_CaseExpression {} -> return True T_CaseExpression {} -> return True
T_HereDoc {} -> return True T_HereDoc {} -> return True
@ -1950,6 +1960,10 @@ getReferencedVariableCommand base@(T_SimpleCommand _ _ (T_NormalWord _ (T_Litera
"declare" -> if "x" `elem` getFlags base "declare" -> if "x" `elem` getFlags base
then concatMap getReference rest then concatMap getReference rest
else [] else []
"trap" ->
case rest of
head:_ -> map (\x -> (head, head, x)) $ getVariablesFromLiteralToken head
_ -> []
_ -> [] _ -> []
where where
getReference t@(T_Assignment _ _ name _ value) = [(t, t, name)] getReference t@(T_Assignment _ _ name _ value) = [(t, t, name)]
@ -2013,8 +2027,32 @@ getReferencedVariables t =
TA_Expansion id _ -> maybeToList $ do TA_Expansion id _ -> maybeToList $ do
str <- getLiteralStringExt (const $ return "#") t str <- getLiteralStringExt (const $ return "#") t
return (t, t, getBracedReference str) return (t, t, getBracedReference str)
T_Assignment id Append str _ _ -> [(t, t, str)] T_Assignment id mode str _ word ->
(if mode == Append then [(t, t, str)] else []) ++ (specialReferences str t word)
x -> getReferencedVariableCommand x x -> getReferencedVariableCommand x
where
-- Try to reduce false positives for unused vars only referenced from evaluated vars
specialReferences name base word =
if name `elem` [
"PS1", "PS2", "PS3", "PS4",
"PROMPT_COMMAND"
]
then
map (\x -> (base, base, x)) $
getVariablesFromLiteralToken word
else []
-- Try to get referenced variables from a literal string like "$foo"
-- Ignores tons of cases like arithmetic evaluation and array indices.
prop_getVariablesFromLiteral1 =
getVariablesFromLiteral "$foo${bar//a/b}$BAZ" == ["foo", "bar", "BAZ"]
getVariablesFromLiteral string =
map (!! 0) $ getAllMatches variableRegex string
where
variableRegex = mkRegex "\\$\\{?([A-Za-z0-9_]+)"
getVariablesFromLiteralToken token =
getVariablesFromLiteral (fromJust $ getLiteralStringExt (const $ return " ") token)
getVariableFlow shell parents t = getVariableFlow shell parents t =
let (_, stack) = runState (doStackAnalysis startScope endScope t) [] let (_, stack) = runState (doStackAnalysis startScope endScope t) []
@ -2277,6 +2315,8 @@ prop_checkUnused16= verifyNotTree checkUnusedAssignments "foo=5; declare -x foo"
prop_checkUnused17= verifyNotTree checkUnusedAssignments "read -i 'foo' -e -p 'Input: ' bar; $bar;" prop_checkUnused17= verifyNotTree checkUnusedAssignments "read -i 'foo' -e -p 'Input: ' bar; $bar;"
prop_checkUnused18= verifyNotTree checkUnusedAssignments "a=1; arr=( [$a]=42 ); echo \"${arr[@]}\"" prop_checkUnused18= verifyNotTree checkUnusedAssignments "a=1; arr=( [$a]=42 ); echo \"${arr[@]}\""
prop_checkUnused19= verifyNotTree checkUnusedAssignments "a=1; let b=a+1; echo $b" prop_checkUnused19= verifyNotTree checkUnusedAssignments "a=1; let b=a+1; echo $b"
prop_checkUnused20= verifyNotTree checkUnusedAssignments "a=1; PS1='$a'"
prop_checkUnused21= verifyNotTree checkUnusedAssignments "a=1; trap 'echo $a' INT"
checkUnusedAssignments params t = snd $ runWriter (mapM_ checkAssignment flow) checkUnusedAssignments params t = snd $ runWriter (mapM_ checkAssignment flow)
where where
flow = variableFlow params flow = variableFlow params