Two different unary operators chained on one operand

ID

objectivec.correctness.multiple_unary_operator

Severity

low

Remediation Complexity

medium

Remediation Risk

low

Remediation Effort

low

Resource

Suspicious Code

Language

Objective-C

Description

Reports an operand carrying two different unary prefix operators in a row - !~value, !-value, ~!flag, ~-value, -!flag, -~value. Where the outer operator is an arithmetic -, the chain is only reported when it clearly starts an expression (after =, return, ( or ,), so a subtraction such as total - !flag is not reported. The same operator applied twice (!!, ~~) is reported by the no-double-operators rule instead, and occurrences inside a comment or a string literal are not reported.

Rationale

Each of these chains means something surprising. ~!flag complements a value that is only ever 0 or 1, producing -1 or -2, which is almost never what a flag is for. !~value is true only when value is exactly -1, and !-value is simply !value with a negation that changes nothing. -~value and ~-value are the arithmetic identities value + 1 and value - 1 written as bit tricks. In every case the reader has to reconstruct the operator precedence and the two’s-complement representation to recover an intent the expression could have stated directly - and the usual cause is a keystroke, a ! typed next to a ~, rather than a deliberate choice.

The following code illustrates the pattern detected by this rule:

@implementation BitReader
- (BOOL)isSentinel:(NSInteger)value {
    // FLAGGED: Two different unary operators chained on one operand
    return !~value;
}

- (NSInteger)clamp:(NSInteger)value { return value; }
@end

Remediation

Write the condition the chain was standing in for. Compare against the value you mean - value == -1 for !~value, !flag for !-flag - or use the plain arithmetic, value + 1 instead of -~value. Where a boolean and a bit mask are genuinely both in play, convert explicitly (flag ? kAllBits : 0) so the two domains stay separate.

Configuration

This detector does not need any configuration.

© 2026 Xygeni. All rights reserved