`LoopConditionChecker` fails to resolve compile-time constant loop bounds, missing genuine infinite loops
- Dominant language
- Java
- Stars
- 7.2k
- Forks
- 820
- Avg merge
- 5h 9m
- Merged PRs (30d)
- 50
Description
### Error Prone version
Error Prone 2.49.0 (javac plugin) — javac 21.0.8, source/target 21.
### Check name
[LoopConditionChecker](https://errorprone.info/bugpattern/LoopConditionChecker)
### Description
`LoopConditionChecker` flags loops whose condition variable(s) are never modified in the loop body (a no-op or infinite loop). The check is sensitive to the *syntactic* form of the loop bound rather than its compile-time-constant value: replacing the literal `1` with a `static final int ONE = 1` — which javac inlines as the constant `1` — silences the diagnostic, even though the loop is byte-for-byte identical at runtime and is still an infinite loop.
### Reproducer
```java
// BEFORE — LoopConditionChecker fires on the second loop
class C {
void foo() {
for (int i = 0; i < 1; i++) {} // i is modified -> not flagged
for (int i = 0; i < 1; foo()) {} // i never modified -> FLAGGED
}
}
```
```java
// AFTER — semantically identical (ONE is the constant 1), rule no longer fires
class C { static final int ONE = 1;
void foo() {
for (int i = 0; i < ONE; i++) {}
for (int i = 0; i < ONE; foo()) {} // still an infinite loop, NOT flagged
}
}
```
### Expected behavior
`LoopConditionChecker` should report the same finding on BEFORE and AFTER. `ONE` is a compile-time constant equal to `1`, so `i < ONE` and `i < 1` are identical, and the second loop is an infinite loop in both forms.
### Actual behavior
- BEFORE: 1 finding — `condition variable(s) never modified in loop body: i` on the `for (int i = 0; i < 1; foo())` loop.
- AFTER: 0 findings. The checker bails out once the bound is a named constant instead of a literal, failing to constant-fold the condition operand.
Contributor guide
Assessment
This issue has not been assessed yet.