Warn when $? refers to echo or condition (ref #2541)

This commit is contained in:
Vidar Holen 2022-07-23 09:38:58 -07:00
parent b261ec24f9
commit 5cf6e01ce9
4 changed files with 42 additions and 0 deletions

View file

@ -205,6 +205,7 @@ nodeChecks = [
,checkBatsTestDoesNotUseNegation
,checkCommandIsUnreachable
,checkSpacefulnessCfg
,checkOverwrittenExitCode
]
optionalChecks = map fst optionalTreeChecks
@ -4876,5 +4877,41 @@ checkCommandIsUnreachable params t =
_ -> return ()
where id = getId t
prop_checkOverwrittenExitCode1 = verify checkOverwrittenExitCode "x; [ $? -eq 1 ] || [ $? -eq 2 ]"
prop_checkOverwrittenExitCode2 = verifyNot checkOverwrittenExitCode "x; [ $? -eq 1 ]"
prop_checkOverwrittenExitCode3 = verify checkOverwrittenExitCode "x; echo \"Exit is $?\"; [ $? -eq 0 ]"
prop_checkOverwrittenExitCode4 = verifyNot checkOverwrittenExitCode "x; [ $? -eq 0 ]"
checkOverwrittenExitCode params t =
case t of
T_DollarBraced id _ val | getLiteralString val == Just "?" -> check id
_ -> return ()
where
check id = sequence_ $ do
state <- CF.getIncomingState (cfgAnalysis params) id
let exitCodeIds = CF.exitCodes state
guard . not $ S.null exitCodeIds
let idToToken = idMap params
exitCodeTokens <- sequence $ map (\k -> Map.lookup k idToToken) $ S.toList exitCodeIds
return $ do
when (all isCondition exitCodeTokens) $
warn id 2319 "This $? refers to a condition, not a command. Assign to a variable to avoid it being overwritten."
when (all isPrinting exitCodeTokens) $
warn id 2320 "This $? refers to echo/printf, not a previous command. Assign to variable to avoid it being overwritten."
isCondition t =
case t of
T_Condition {} -> True
T_SimpleCommand {} -> getCommandName t == Just "test"
_ -> False
isPrinting t =
case getCommandBasename t of
Just "echo" -> True
Just "printf" -> True
_ -> False
return []
runTests = $( [| $(forAllProperties) (quickCheckWithResult (stdArgs { maxSuccess = 1 }) ) |])