Reversed Compound Operator
ID |
kotlin.reversed_compound_operator |
Severity |
high |
Remediation Complexity |
trivial |
Remediation Risk |
low |
Remediation Effort |
low |
Resource |
Reliability |
Language |
Kotlin |
Tags |
reliability, suspicious-operator |
Description
Reports an assignment written as total =- delta, total =+ delta or flag =! other, where the
= is glued to the following unary operator and the operand is set off by a space.
Kotlin has no =-, =+ or =! operator. The statement is a plain assignment of a negated,
signed or inverted value — but the spacing makes it read as the compound assignment -= or +=,
or as the != comparison.
Rationale
var total = 0
total =+ delta // overwrites total with +delta; `total += delta` was meant
total =- delta // overwrites total with -delta; `total -= delta` was meant
var flag = false
flag =! other // overwrites flag with !other; `flag != other` was probably meant
The mismatch is entirely silent: the code compiles, runs, and does something perfectly sensible —
just not what the layout advertises. total =+ delta throws away every previous accumulation on
each pass, which in a loop looks like an accumulator that keeps only the last value, and
flag =! other overwrites a flag where a comparison was intended.
Because the defect lives in the spacing rather than in the tree, only that one layout is reported:
the unary operator must sit immediately after the =, and whitespace must separate it from its
operand. The deliberate total = -delta and the unambiguous total =-delta are both left alone,
and so is every compound assignment.
The three operators covered are Kotlin’s whole set of candidates. Kotlin’s grammar admits exactly
five prefix unary operators — `, `--`, `-`, `+`, `!` — and only `-`, `+` and `!` spell a real
operator when reversed (`-=`, `+=` and the `!=` comparison). There is no `= or --=, and Kotlin
has no bitwise-complement operator at all: and, or and xor are infix functions with no prefix
form.
Finally, the right-hand side must be the signed value. total =- delta + 1 assigns (-delta) + 1,
which no compound operator would have produced, so it is not reported as a typo for -=.
Remediation
Decide which of the two readings was intended and write it unambiguously.
total += delta // accumulate — what the layout suggested
total = +delta // assign the signed value — spaced so it reads that way
if (flag != other) { ... } // compare
flag = !other // assign the inverted value
A consistent spacing convention around operators prevents the whole class: with a space on both
sides of = and none between a unary operator and its operand, the two readings can never look
alike.