Skip to content

Commit bc5cded

Browse files
committed
Suppress SC2319/SC2320 when $? is assigned to a variable (fixes #3486)
1 parent 9af7ee2 commit bc5cded

1 file changed

Lines changed: 33 additions & 2 deletions

File tree

src/ShellCheck/Analytics.hs

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5094,9 +5094,14 @@ prop_checkOverwrittenExitCode2 = verifyNot checkOverwrittenExitCode "x; [ $? -eq
50945094
prop_checkOverwrittenExitCode3 = verify checkOverwrittenExitCode "x; echo \"Exit is $?\"; [ $? -eq 0 ]"
50955095
prop_checkOverwrittenExitCode4 = verifyNot checkOverwrittenExitCode "x; [ $? -eq 0 ] && echo Success"
50965096
prop_checkOverwrittenExitCode5 = verify checkOverwrittenExitCode "x; if [ $? -eq 0 ]; then var=$?; fi"
5097+
prop_checkOverwrittenExitCode5a = verify checkOverwrittenExitCode "x; if [ $? -eq 0 ]; then exit $?; fi"
50975098
prop_checkOverwrittenExitCode6 = verify checkOverwrittenExitCode "x; [ $? -gt 0 ] && fail=$?"
5099+
prop_checkOverwrittenExitCode6a = verify checkOverwrittenExitCode "x; [ $? -eq 0 ] && exit $?"
50985100
prop_checkOverwrittenExitCode7 = verifyNot checkOverwrittenExitCode "[ 1 -eq 2 ]; status=$?"
50995101
prop_checkOverwrittenExitCode8 = verifyNot checkOverwrittenExitCode "[ 1 -eq 2 ]; exit $?"
5102+
prop_checkOverwrittenExitCode9 = verifyNot checkOverwrittenExitCode "[[ -e \"./lockfile\" ]] || retval=$?"
5103+
prop_checkOverwrittenExitCode10 = verifyNot checkOverwrittenExitCode "[ -e \"./lockfile\" ] || retval=$?"
5104+
prop_checkOverwrittenExitCode11 = verifyNot checkOverwrittenExitCode "[ 1 -eq 2 ] && status=$?"
51005105
checkOverwrittenExitCode params t =
51015106
case t of
51025107
T_DollarBraced id _ val | getLiteralString val == Just "?" -> check id
@@ -5110,10 +5115,16 @@ checkOverwrittenExitCode params t =
51105115

51115116
let idToToken = idMap params
51125117
exitCodeTokens <- traverse (\k -> Map.lookup k idToToken) $ S.toList exitCodeIds
5118+
let inAssignment = isInAssignment id
5119+
condHasDollarQ = conditionContainsDollarQuestion id exitCodeIds
5120+
suppress = inAssignment && not condHasDollarQ
51135121
return $ do
5114-
when (all isCondition exitCodeTokens && not (usedUnconditionally cfga t exitCodeIds)) $
5122+
when (all isCondition exitCodeTokens
5123+
&& not (usedUnconditionally cfga t exitCodeIds)
5124+
&& not suppress) $
51155125
warn id 2319 "This $? refers to a condition, not a command. Assign to a variable to avoid it being overwritten."
5116-
when (all isPrinting exitCodeTokens) $
5126+
when (all isPrinting exitCodeTokens
5127+
&& not suppress) $
51175128
warn id 2320 "This $? refers to echo/printf, not a previous command. Assign to variable to avoid it being overwritten."
51185129

51195130
isCondition t =
@@ -5133,6 +5144,26 @@ checkOverwrittenExitCode params t =
51335144
Just "printf" -> True
51345145
_ -> False
51355146

5147+
isInAssignment tokenId =
5148+
let token = Map.lookup tokenId (idMap params)
5149+
in maybe False (\tok -> any isAssignmentToken $ getPath (parentMap params) tok) token
5150+
where
5151+
isAssignmentToken (T_Assignment _ _ _ _ _) = True
5152+
isAssignmentToken _ = False
5153+
5154+
conditionContainsDollarQuestion tokenId exitIds =
5155+
let tree = parentMap params
5156+
tokenMap = idMap params
5157+
condTokens = mapMaybe (`Map.lookup` tokenMap) (S.toList exitIds)
5158+
dollarQTokens = [(tid, tok) | (tid, tok) <- Map.toList tokenMap,
5159+
tid /= tokenId,
5160+
isDollarQ tok]
5161+
isDollarQ (T_DollarBraced _ _ val) = getLiteralString val == Just "?"
5162+
isDollarQ _ = False
5163+
in any (\(_, dqToken) ->
5164+
any (\cond -> isParentOf tree cond dqToken) condTokens
5165+
) dollarQTokens
5166+
51365167

51375168
prop_checkUnnecessaryArithmeticExpansionIndex1 = verify checkUnnecessaryArithmeticExpansionIndex "a[$((1+1))]=n"
51385169
prop_checkUnnecessaryArithmeticExpansionIndex2 = verifyNot checkUnnecessaryArithmeticExpansionIndex "a[1+1]=n"

0 commit comments

Comments
 (0)