Increment, decrement or assignment in the right operand of && or ||
ID |
objectivec.maintainability.side_effect_in_short_circuit |
Severity |
low |
Remediation Complexity |
medium |
Remediation Risk |
low |
Remediation Effort |
medium |
Resource |
Suspicious Code |
Language |
Objective-C |
Description
Reports an increment, a decrement or an assignment written in the right operand of && or ||. A side effect in the left operand, which always runs, is not reported, and neither is a statement in the body of a one-line conditional or an argument that follows a comma. A message send whose side effect is hidden inside the method it calls is beyond a syntactic check and is not reported.
Rationale
&& and || do not evaluate their right operand when the left one already decides the result, so the side effect happens on some paths and not others - and which ones depends on the order the conditions happen to be written in. The counter then drifts, or the variable is left holding a stale value, only for the inputs that take the short-circuiting path, which is the combination least likely to be covered by a test.
The following code illustrates the pattern detected by this rule:
@implementation Parser
- (BOOL)scanUpTo:(NSInteger)limit {
NSInteger index = 0;
// FLAGGED: Increment, decrement or assignment in the right operand of && or ||
while (index < limit && self.buffer[index++] != 0) {
[self consume];
}
// FLAGGED: Increment, decrement or assignment in the right operand of && or ||
if (self.enabled && ++self.attempts > 3) {
return NO;
}
return YES;
}
@end
Remediation
Move the side effect out of the condition and onto its own statement above, so it runs exactly once whatever the other operand evaluates to. Where it genuinely must be conditional, write the nested if that says so, rather than leaving the reader to work out the evaluation order.