Improve detection of for loops with single values

This commit is contained in:
Vidar Holen 2020-03-15 11:29:32 -07:00
parent d28c8f883f
commit a57f6d2886
3 changed files with 23 additions and 6 deletions

View File

@ -11,6 +11,7 @@
- SC2255: Suggest using `$((..))` in `[ 2*3 -eq 6 ]`
- SC2256: Warn about translated strings that are known variables
- SC2257: Warn about arithmetic mutation in redirections
- SC2258: Warn about trailing commas in for loop elements
### Changed
- SC2230: 'command -v' suggestion is now off by default (-i deprecate-which)

View File

@ -47,6 +47,7 @@ willSplit x =
T_BraceExpansion {} -> True
T_Glob {} -> True
T_Extglob {} -> True
T_DoubleQuoted _ l -> any willBecomeMultipleArgs l
T_NormalWord _ l -> any willSplit l
_ -> False

View File

@ -578,16 +578,30 @@ prop_checkForInQuoted4 = verify checkForInQuoted "for f in 1,2,3; do true; done"
prop_checkForInQuoted4a = verifyNot checkForInQuoted "for f in foo{1,2,3}; do true; done"
prop_checkForInQuoted5 = verify checkForInQuoted "for f in ls; do true; done"
prop_checkForInQuoted6 = verifyNot checkForInQuoted "for f in \"${!arr}\"; do true; done"
prop_checkForInQuoted7 = verify checkForInQuoted "for f in ls, grep, mv; do true; done"
prop_checkForInQuoted8 = verify checkForInQuoted "for f in 'ls', 'grep', 'mv'; do true; done"
prop_checkForInQuoted9 = verifyNot checkForInQuoted "for f in 'ls,' 'grep,' 'mv'; do true; done"
checkForInQuoted _ (T_ForIn _ f [T_NormalWord _ [word@(T_DoubleQuoted id list)]] _)
| any (\x -> willSplit x && not (mayBecomeMultipleArgs x)) list
|| (fmap wouldHaveBeenGlob (getLiteralString word) == Just True) =
err id 2066 "Since you double quoted this, it will not word split, and the loop will only run once."
checkForInQuoted _ (T_ForIn _ f [T_NormalWord _ [T_SingleQuoted id _]] _) =
warn id 2041 "This is a literal string. To run as a command, use $(..) instead of '..' . "
checkForInQuoted _ (T_ForIn _ f [T_NormalWord _ [T_Literal id s]] _) =
if ',' `elem` s && '{' `notElem` s
then warn id 2042 "Use spaces, not commas, to separate loop elements."
else warn id 2043 "This loop will only ever run once for a constant value. Did you perhaps mean to loop over dir/*, $var or $(cmd)?"
checkForInQuoted _ (T_ForIn _ _ [single] _) | fromMaybe False $ fmap (',' `elem`) $ getUnquotedLiteral single =
warn (getId single) 2042 "Use spaces, not commas, to separate loop elements."
checkForInQuoted _ (T_ForIn _ _ [single] _) | not (willSplit single) && not (mayBecomeMultipleArgs single) =
warn (getId single) 2043 "This loop will only ever run once. Bad quoting or missing glob/expansion?"
checkForInQuoted params (T_ForIn _ _ multiple _) =
mapM_ f multiple
where
f arg = sequence_ $ do
suffix <- getTrailingUnquotedLiteral arg
string <- getLiteralString suffix
guard $ "," `isSuffixOf` string
return $
warnWithFix (getId arg) 2258
"The trailing comma is part of the value, not a separator. Delete or quote it."
(fixWith [replaceEnd (getId suffix) params 1 ""])
checkForInQuoted _ _ = return ()
prop_checkForInCat1 = verify checkForInCat "for f in $(cat foo); do stuff; done"
@ -1011,8 +1025,9 @@ prop_checkUnquotedN2 = verify checkUnquotedN "[ -n $cow ]"
prop_checkUnquotedN3 = verifyNot checkUnquotedN "[[ -n $foo ]] && echo cow"
prop_checkUnquotedN4 = verify checkUnquotedN "[ -n $cow -o -t 1 ]"
prop_checkUnquotedN5 = verifyNot checkUnquotedN "[ -n \"$@\" ]"
checkUnquotedN _ (TC_Unary _ SingleBracket "-n" (T_NormalWord id [t])) | willSplit t =
err id 2070 "-n doesn't work with unquoted arguments. Quote or use [[ ]]."
checkUnquotedN _ (TC_Unary _ SingleBracket "-n" t) | willSplit t =
unless (any isArrayExpansion $ getWordParts t) $ -- There's SC2198 for these
err (getId t) 2070 "-n doesn't work with unquoted arguments. Quote or use [[ ]]."
checkUnquotedN _ _ = return ()
prop_checkNumberComparisons1 = verify checkNumberComparisons "[[ $foo < 3 ]]"