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

View File

@ -47,6 +47,7 @@ willSplit x =
T_BraceExpansion {} -> True T_BraceExpansion {} -> True
T_Glob {} -> True T_Glob {} -> True
T_Extglob {} -> True T_Extglob {} -> True
T_DoubleQuoted _ l -> any willBecomeMultipleArgs l
T_NormalWord _ l -> any willSplit l T_NormalWord _ l -> any willSplit l
_ -> False _ -> 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_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_checkForInQuoted5 = verify checkForInQuoted "for f in ls; do true; done"
prop_checkForInQuoted6 = verifyNot checkForInQuoted "for f in \"${!arr}\"; 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)]] _) checkForInQuoted _ (T_ForIn _ f [T_NormalWord _ [word@(T_DoubleQuoted id list)]] _)
| any (\x -> willSplit x && not (mayBecomeMultipleArgs x)) list | any (\x -> willSplit x && not (mayBecomeMultipleArgs x)) list
|| (fmap wouldHaveBeenGlob (getLiteralString word) == Just True) = || (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." 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 _]] _) = 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 '..' . " 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]] _) = checkForInQuoted _ (T_ForIn _ _ [single] _) | fromMaybe False $ fmap (',' `elem`) $ getUnquotedLiteral single =
if ',' `elem` s && '{' `notElem` s warn (getId single) 2042 "Use spaces, not commas, to separate loop elements."
then warn id 2042 "Use spaces, not commas, to separate loop elements." checkForInQuoted _ (T_ForIn _ _ [single] _) | not (willSplit single) && not (mayBecomeMultipleArgs single) =
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)?" 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 () checkForInQuoted _ _ = return ()
prop_checkForInCat1 = verify checkForInCat "for f in $(cat foo); do stuff; done" 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_checkUnquotedN3 = verifyNot checkUnquotedN "[[ -n $foo ]] && echo cow"
prop_checkUnquotedN4 = verify checkUnquotedN "[ -n $cow -o -t 1 ]" prop_checkUnquotedN4 = verify checkUnquotedN "[ -n $cow -o -t 1 ]"
prop_checkUnquotedN5 = verifyNot checkUnquotedN "[ -n \"$@\" ]" prop_checkUnquotedN5 = verifyNot checkUnquotedN "[ -n \"$@\" ]"
checkUnquotedN _ (TC_Unary _ SingleBracket "-n" (T_NormalWord id [t])) | willSplit t = checkUnquotedN _ (TC_Unary _ SingleBracket "-n" t) | willSplit t =
err id 2070 "-n doesn't work with unquoted arguments. Quote or use [[ ]]." 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 () checkUnquotedN _ _ = return ()
prop_checkNumberComparisons1 = verify checkNumberComparisons "[[ $foo < 3 ]]" prop_checkNumberComparisons1 = verify checkNumberComparisons "[[ $foo < 3 ]]"