Modulus Result Compared With A Non-Zero Value

ID

swift.no_modulus_direct_equality

Severity

high

Remediation Complexity

trivial

Remediation Risk

low

Remediation Effort

low

Resource

Reliability

Language

Swift

Tags

arithmetic, reliability, suspicious-comparison

Description

Reports an equality comparison between a % expression and a non-zero integer literal, such as value % 2 == 1. Both operand orders are covered, and so is a negated literal (== -1). Comparisons against 0 are not reported.

Rationale

func isOdd(_ value: Int) -> Bool {
    return value % 2 == 1
}

isOdd(3)     // true
isOdd(-3)    // false — and -3 is odd

In Swift the remainder operator keeps the sign of the dividend, so -3 % 2 is -1, not 1. The odd-number test above therefore answers "even" for every negative odd value. The defect survives testing easily: positive inputs behave exactly as intended, and only a negative one — a delta, an offset, a coordinate, a value read from user input — exposes it.

A negated literal has the mirror-image blind spot: value % 2 == -1 is false for every positive odd value.

A dividend that cannot be negative is exempt, because for it the sign rule never applies: a call to abs, a conversion to an unsigned integer type (UInt(value) % 2 == 1), a size-like member read (count, underestimatedCount, length, magnitude), a variable or parameter whose declared type is unsigned, the offset a closure is handed by enumerated() (items.enumerated().filter { idx, _ in idx % 2 == 1 }, where the offset counts from zero upwards), and a dividend that already takes a remainder of its own — the shape of a normalised remainder. Any other dividend is still reported, so no finding is lost when a type cannot be resolved.

Remediation

Compare the remainder with zero, which no sign can change, or normalise the remainder into the non-negative range before comparing it.

// Compare against zero.
func isOdd(_ value: Int) -> Bool {
    return value % 2 != 0
}

// Or normalise the remainder first, when the actual value matters.
func bucket(_ value: Int, _ buckets: Int) -> Int {
    return ((value % buckets) + buckets) % buckets
}

For the parity case specifically, the standard library already answers it without arithmetic:

if value.isMultiple(of: 2) {
    // even, for negative values too
}

© 2026 Xygeni. All rights reserved