No Useless Increment

ID

kotlin.no_useless_increment

Severity

high

Remediation Complexity

trivial

Remediation Risk

low

Remediation Effort

low

Resource

Reliability

Language

Kotlin

Tags

dead-code, reliability, suspicious-assignment

Description

Reports a postfix ++ or -- whose effect is thrown away, in the two shapes where the mistake is unambiguous:

  • return i`, the expression body `fun bump(): Int = i, and a lambda whose last expression is i++ — the postfix form yields the value from before the update, and the var it just changed dies with the call.

  • i = i++ — the right-hand side is the old value of i, written straight back over the incremented one.

Rationale

fun bumpLocal(start: Int): Int {
    var local = start
    return local++          // returns `start`, and the increment is lost with the frame
}

fun rewind() {
    cursor = cursor++       // reads cursor, increments it, then overwrites it with the old value
}

Both compile and run. return local` hands the caller the value from before the increment, and the increment lands in storage that vanishes when the function returns, so it is unobservable — the author meant `return local + 1` or `return local. cursor = cursor++ is a complete no-op: the increment happens and is then overwritten by the value read before it.

The returned-value shape is reported only when the operand is a local var declared in the same function. Storage that survives the call is not a defect and is not reported:

class IdGenerator {
    private var next = 0
    fun nextId(): Int = next++   // OK — the canonical id generator; the property keeps the value
}

fun makeCounter(): () -> Int {
    var i = 0
    return { i++ }               // OK — Kotlin captures a `var` by reference, so `i` survives
}

A prefix return i` is correct, since the returned value *is* the updated one. A bare `i statement is the ordinary way to count and is never reported, and neither is a postfix whose value something consumes — j = i`, `println(i), return i + 1`. A member or indexed target (`box.count = box.count, values[0] = values[0]++) is left alone rather than guessing whether the two sides denote the same storage.

Note that a Kotlin parameter is a val and cannot be incremented at all, so the only operand this rule ever reports on is a local var.

Remediation

Say what the code was meant to say: return the updated value, or increment as a statement of its own.

fun bumpLocal(start: Int): Int = start + 1   // the value the caller wanted

fun rewind() {
    cursor++                                  // the update, as its own statement
}

© 2026 Xygeni. All rights reserved