Fix for unbounded wildcard passed to @NullUnmarked type variable#1577
Conversation
|
This change is part of the following stack:
Change managed by git-spice. |
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## master #1577 +/- ##
=========================================
Coverage 88.20% 88.20%
- Complexity 2934 2938 +4
=========================================
Files 104 104
Lines 9807 9819 +12
Branches 1974 1977 +3
=========================================
+ Hits 8650 8661 +11
- Misses 557 558 +1
Partials 600 600 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
a766d08 to
02032b9
Compare
02032b9 to
6b46cae
Compare
6b46cae to
e046e3c
Compare
e046e3c to
5d6301c
Compare
5d6301c to
9c7885b
Compare
9c7885b to
b365629
Compare
b365629 to
8eefd6b
Compare
8eefd6b to
f4da62e
Compare
f4da62e to
a877763
Compare
d790baf to
d9c9900
Compare
d9c9900 to
4f9db4f
Compare
4f9db4f to
86870e5
Compare
86870e5 to
5244672
Compare
5244672 to
fda7118
Compare
WalkthroughThis PR enhances NullAway's generics handling by threading Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@nullaway/src/main/java/com/uber/nullaway/generics/GenericsUtils.java`:
- Around line 109-117: The code silently treats
methodSymbol.getTypeParameters().indexOf(typeVariableSymbol) == -1 as "no
override" and skips calling handler.onOverrideMethodTypeVariableUpperBound;
change this to perform a fallback lookup when indexOf returns -1: in
GenericsUtils (the branch where enclosingElement instanceof Symbol.MethodSymbol
methodSymbol and typeVarElement instanceof Symbol.TypeVariableSymbol
typeVariableSymbol), if indexOf yields -1, scan methodSymbol.getTypeParameters()
manually to find a matching TypeVariableSymbol (compare by symbol
identity/equality and, if needed, by simple name via
typeVariableSymbol.getSimpleName()) to derive a valid typeVarIndex, then use
that index to call handler.onOverrideMethodTypeVariableUpperBound(methodSymbol,
typeVarIndex, state) as before so method-type-variable overrides are not
dropped.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 6d81b54f-d990-4615-b478-06b84e81f2ee
📒 Files selected for processing (5)
nullaway/src/main/java/com/uber/nullaway/generics/CheckIdenticalNullabilityVisitor.javanullaway/src/main/java/com/uber/nullaway/generics/ConstraintSolverImpl.javanullaway/src/main/java/com/uber/nullaway/generics/GenericsChecks.javanullaway/src/main/java/com/uber/nullaway/generics/GenericsUtils.javanullaway/src/test/java/com/uber/nullaway/jspecify/WildcardTests.java
| if (enclosingElement instanceof Symbol.MethodSymbol methodSymbol | ||
| && typeVarElement instanceof Symbol.TypeVariableSymbol typeVariableSymbol) { | ||
| int typeVarIndex = methodSymbol.getTypeParameters().indexOf(typeVariableSymbol); | ||
| // TODO typeVarIndex is -1 in some cases; see test | ||
| // com.uber.nullaway.jspecify.GenericMethodTests.instanceGenericMethodWithMethodRefArgument. | ||
| // Investigate further. | ||
| if (typeVarIndex >= 0 | ||
| && handler.onOverrideMethodTypeVariableUpperBound(methodSymbol, typeVarIndex, state)) { | ||
| return true; |
There was a problem hiding this comment.
Don't silently drop method-type-variable handler overrides when the index lookup fails.
If getTypeParameters().indexOf(typeVariableSymbol) returns -1, this helper skips onOverrideMethodTypeVariableUpperBound(...) and falls back to annotation-only logic. Since upperBoundIsNullable(...) now feeds both wildcard upper-bound computation here and ConstraintSolverImpl.getState(...), the modeled nullable upper bound is still lost for the method-type-variable cases already called out by the TODO. Please add a fallback lookup instead of treating -1 as "no override".
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@nullaway/src/main/java/com/uber/nullaway/generics/GenericsUtils.java` around
lines 109 - 117, The code silently treats
methodSymbol.getTypeParameters().indexOf(typeVariableSymbol) == -1 as "no
override" and skips calling handler.onOverrideMethodTypeVariableUpperBound;
change this to perform a fallback lookup when indexOf returns -1: in
GenericsUtils (the branch where enclosingElement instanceof Symbol.MethodSymbol
methodSymbol and typeVarElement instanceof Symbol.TypeVariableSymbol
typeVariableSymbol), if indexOf yields -1, scan methodSymbol.getTypeParameters()
manually to find a matching TypeVariableSymbol (compare by symbol
identity/equality and, if needed, by simple name via
typeVariableSymbol.getSimpleName()) to derive a valid typeVarIndex, then use
that index to call handler.onOverrideMethodTypeVariableUpperBound(methodSymbol,
typeVarIndex, state) as before so method-type-variable overrides are not
dropped.
There was a problem hiding this comment.
What kind of fallback loop?
There was a problem hiding this comment.
I think this is a weird corner case that doesn't need to be handled now
There was a problem hiding this comment.
@msridhar, understood — the existing TODO already documents the known -1 case, so this can be deferred. Would you like me to open a follow-up GitHub issue to track it, or shall I just resolve this review comment?
🧠 Learnings used
Learnt from: msridhar
Repo: uber/NullAway PR: 1485
File: nullaway/src/main/java/com/uber/nullaway/NullAway.java:2119-2128
Timestamp: 2026-03-20T15:34:10.657Z
Learning: In this repo (uber/NullAway), don’t annotate local variables with `Nullable` or `NonNull`. NullAway infers nullability for local variables automatically, so adding these annotations to locals is incorrect style for this codebase.
There was a problem hiding this comment.
@msridhar — the loop I had in mind was a linear name-based scan as a fallback:
if (typeVarIndex < 0) {
List<Symbol.TypeVariableSymbol> typeParams = methodSymbol.getTypeParameters();
for (int i = 0; i < typeParams.size(); i++) {
if (typeParams.get(i).getSimpleName()
.equals(typeVariableSymbol.getSimpleName())) {
typeVarIndex = i;
break;
}
}
}That said, I realise the root cause of why indexOf returns -1 in the first place hasn't been investigated yet (per the existing TODO pointing at GenericMethodTests.instanceGenericMethodWithMethodRefArgument). If the typeVariableSymbol reaching this point is a specialised/substituted copy of the original method's type variable (which javac sometimes produces during inference), then a name-based fallback could accidentally map to the wrong index or mask a deeper problem.
Given that uncertainty, it's probably more correct to first understand why indexOf fails — whether it's an identity vs. equality issue with javac's Symbol, a different MethodSymbol being used as enclosingElement, or something else — before deciding what the right fallback is.
Would you like to open a follow-up issue to track that investigation?
🧠 Learnings used
Learnt from: msridhar
Repo: uber/NullAway PR: 1485
File: nullaway/src/main/java/com/uber/nullaway/NullAway.java:2119-2128
Timestamp: 2026-03-20T15:34:10.657Z
Learning: In this repo (uber/NullAway), don’t annotate local variables with `Nullable` or `NonNull`. NullAway infers nullability for local variables automatically, so adding these annotations to locals is incorrect style for this codebase.
See the new test case
unboundWildcardTypeVarUnmarked. Previously, for an unbound wildcard, we neglected to check whether the corresponding type variable was in@NullUnmarkedcode. If the type variable is in a@NullUnmarkedscope, we treat its upper bound as@Nullable. Most of the code in this PR is passing around additional parameters so we can move the methods for reasoning about upper bounds toGenericsUtilsand share the reasoning.Summary by CodeRabbit