Warn about unnecessary subshells in tests
This commit is contained in:
parent
77546fba2f
commit
1d8047cce1
|
@ -1,5 +1,6 @@
|
||||||
## Latest - ???
|
## Latest - ???
|
||||||
### Added
|
### Added
|
||||||
|
- SC2233/SC2234/SC2235: Suggest removing or replacing (..) around tests
|
||||||
- SC2232: Warn about invalid arguments to sudo
|
- SC2232: Warn about invalid arguments to sudo
|
||||||
- SC2231: Suggest quoting expansions in for loop globs
|
- SC2231: Suggest quoting expansions in for loop globs
|
||||||
- SC2229: Warn about 'read $var'
|
- SC2229: Warn about 'read $var'
|
||||||
|
|
|
@ -167,6 +167,7 @@ nodeChecks = [
|
||||||
,checkEmptyCondition
|
,checkEmptyCondition
|
||||||
,checkPipeToNowhere
|
,checkPipeToNowhere
|
||||||
,checkForLoopGlobVariables
|
,checkForLoopGlobVariables
|
||||||
|
,checkSubshelledTests
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -2921,5 +2922,63 @@ checkForLoopGlobVariables _ t =
|
||||||
suggest t = info (getId t) 2231
|
suggest t = info (getId t) 2231
|
||||||
"Quote expansions in this for loop glob to prevent wordsplitting, e.g. \"$dir\"/*.txt ."
|
"Quote expansions in this for loop glob to prevent wordsplitting, e.g. \"$dir\"/*.txt ."
|
||||||
|
|
||||||
|
prop_checkSubshelledTests1 = verify checkSubshelledTests "a && ( [ b ] || ! [ c ] )"
|
||||||
|
prop_checkSubshelledTests2 = verify checkSubshelledTests "( [ a ] )"
|
||||||
|
prop_checkSubshelledTests3 = verify checkSubshelledTests "( [ a ] && [ b ] || test c )"
|
||||||
|
checkSubshelledTests params t =
|
||||||
|
case t of
|
||||||
|
T_Subshell id list | isSubshelledTest t ->
|
||||||
|
case () of
|
||||||
|
-- Special case for if (test) and while (test)
|
||||||
|
_ | isCompoundCondition (getPath (parentMap params) t) ->
|
||||||
|
style id 2233 "Remove superfluous (..) around condition."
|
||||||
|
|
||||||
|
-- Special case for ([ x ])
|
||||||
|
_ | isSingleTest list ->
|
||||||
|
style id 2234 "Remove superfluous (..) around test command."
|
||||||
|
|
||||||
|
-- General case for ([ x ] || [ y ] && etc)
|
||||||
|
_ -> style id 2235 "Use { ..; } instead of (..) to avoid subshell overhead."
|
||||||
|
_ -> return ()
|
||||||
|
where
|
||||||
|
|
||||||
|
isSingleTest cmds =
|
||||||
|
case cmds of
|
||||||
|
[c] | isTestCommand c -> True
|
||||||
|
_ -> False
|
||||||
|
|
||||||
|
isSubshelledTest t =
|
||||||
|
case t of
|
||||||
|
T_Subshell _ list -> all isSubshelledTest list
|
||||||
|
T_AndIf _ a b -> isSubshelledTest a && isSubshelledTest b
|
||||||
|
T_OrIf _ a b -> isSubshelledTest a && isSubshelledTest b
|
||||||
|
T_Annotation _ _ t -> isSubshelledTest t
|
||||||
|
_ -> isTestCommand t
|
||||||
|
|
||||||
|
isTestCommand t =
|
||||||
|
case t of
|
||||||
|
T_Banged _ t -> isTestCommand t
|
||||||
|
T_Pipeline _ [] [T_Redirecting _ _ T_Condition {}] -> True
|
||||||
|
T_Pipeline _ [] [T_Redirecting _ _ cmd] -> cmd `isCommand` "test"
|
||||||
|
_ -> False
|
||||||
|
|
||||||
|
-- Check if a T_Subshell is used as a condition, e.g. if ( test )
|
||||||
|
-- This technically also triggers for `if true; then ( test ); fi`
|
||||||
|
-- but it's still a valid suggestion.
|
||||||
|
isCompoundCondition chain =
|
||||||
|
case dropWhile skippable (drop 1 chain) of
|
||||||
|
T_IfExpression {} : _ -> True
|
||||||
|
T_WhileExpression {} : _ -> True
|
||||||
|
T_UntilExpression {} : _ -> True
|
||||||
|
_ -> False
|
||||||
|
|
||||||
|
-- Skip any parent of a T_Subshell until we reach something interesting
|
||||||
|
skippable t =
|
||||||
|
case t of
|
||||||
|
T_Redirecting _ [] _ -> True
|
||||||
|
T_Pipeline _ [] _ -> True
|
||||||
|
T_Annotation {} -> True
|
||||||
|
_ -> False
|
||||||
|
|
||||||
return []
|
return []
|
||||||
runTests = $( [| $(forAllProperties) (quickCheckWithResult (stdArgs { maxSuccess = 1 }) ) |])
|
runTests = $( [| $(forAllProperties) (quickCheckWithResult (stdArgs { maxSuccess = 1 }) ) |])
|
||||||
|
|
Loading…
Reference in New Issue