Skip to content

Conversation

@Suvrat1629
Copy link

Fixed a Checker Framework crash (NPE in AnnotationUtils.annotationName) when computing LUB for captured type variables from wildcard capture.
The bug occurred because primary annotations were lost on bounds during special-case handling for captured types/wildcards in lubWildcard.

Fix: After merging bounds in lubWildcard, explicitly call lubPrimaryAnnotations on the upper bound to propagate qualifiers correctly when one side lacks primaries.
This prevents null annotations in hierarchies, eliminating the crash.
Added test checker/tests/nullness/Test6872.java that previously crashed and now passes cleanly.

Fixes #6872

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 6, 2026

📝 Walkthrough

Walkthrough

This change addresses a null pointer exception that occurred during least upper bound computation when processing switch expressions containing method references. A regression test file was added to verify the fix, and defensive null checks were implemented in the lubPrimaryOnBoundedType method of AtmLubVisitor.java. These checks handle cases where lower-bound or upper-bound annotations are null, preventing them from being passed to QualifierHierarchy or AnnotationUtils methods that would otherwise fail.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The PR addresses all key objectives from issue #6872: defensive null checks in AtmLubVisitor.lubPrimaryOnBoundedType prevent NPE crashes, regression test Test6872.java reproduces the switch expression scenario, and qualifier-hierarchy logic robustness is improved.
Out of Scope Changes check ✅ Passed All changes are directly scoped to fixing the NPE in AtmLubVisitor and adding regression test coverage; no extraneous modifications detected.
✨ Finishing touches
  • 📝 Generate docstrings

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 66d2d16 and f263c80.

📒 Files selected for processing (2)
  • checker/tests/nullness/Test6872.java
  • framework/src/main/java/org/checkerframework/framework/util/AtmLubVisitor.java
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-11-02T02:18:00.536Z
Learnt from: mernst
Repo: typetools/checker-framework PR: 7354
File: annotation-file-utilities/tests/LocalMultipleManyMethodsShifted.java:14-14
Timestamp: 2025-11-02T02:18:00.536Z
Learning: In the Checker Framework repository, when doing refactoring PRs (such as preferring isEmpty() over size() comparisons), test files should not be changed. Tests should remain stable to preserve their exact patterns for annotation processing and bytecode verification purposes.

Applied to files:

  • checker/tests/nullness/Test6872.java
🔇 Additional comments (4)
framework/src/main/java/org/checkerframework/framework/util/AtmLubVisitor.java (3)

354-357: LGTM! Appropriate null check for missing hierarchy annotation.

The null check correctly handles the case where findAnnotationInHierarchy returns null because type2 doesn't have an annotation in the same hierarchy as lower1. This is expected behavior and the defensive check is appropriate.


360-364: LGTM! Defensive null checks prevent passing null to QualifierHierarchy methods.

The null checks appropriately guard against null effective annotations before passing them to isSubtypeShallow and leastUpperBoundShallow methods at lines 366-376. This prevents the NPE described in issue #6872.


343-348: Add null protection at line 114-125 for consistency.

While the defensive null checks at lines 343-348, 354-357, and 360-364 appropriately guard against null entries in AnnotationMirrorSet, the earlier iteration at line 114 uses the same findEffectiveLowerBoundAnnotations() method without null protection. Since the code acknowledges that the set "may (incorrectly) contain null entries," apply consistent defensive guards to the iteration at lines 114-125 as well to prevent potential NPE:

for (AnnotationMirror lowerBound : lowerBounds) {
  if (lowerBound == null) {
    continue;
  }
  // ... existing logic
}

The null checks in the reviewed code are correct and necessary; however, the same defensive pattern should be applied throughout the class wherever findEffectiveLowerBoundAnnotations() results are iterated.

checker/tests/nullness/Test6872.java (1)

1-18: Minimal regression test appropriately reproduces the NPE scenario.

The test correctly exercises the bug fix by using a switch expression that returns either a method reference Test6872::compare or a Comparator<Object> parameter, forcing LUB computation on captured type variables that previously caused the NPE.

Since this is a regression test for a crash bug, compile-only verification is appropriate—the test simply ensures the Checker Framework doesn't crash during type-checking. No assertions are needed.


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@Suvrat1629 Suvrat1629 changed the title Fix NPE in AtmLubVisitor for captured types in switch expressions (#6872) Fix NPE in AtmLubVisitor for captured types in switch expressions Jan 6, 2026
@mernst
Copy link
Member

mernst commented Jan 16, 2026

Thanks for your pull request. We appreciate it.

Although you describe this as a fix, the pull request does not correct the underlying problem, which is that an AnnotationMirrorSet is empty. The pull request works around the problem by returning a (possibly incorrect) value rather than crashing. I don't think this is a desirable change. Although it prevents a crash, it masks a real problem. When user code triggers that problem, the Checker Framework will behave bizarrely, making diagnosing the issue quite difficult.

I agree that users should not see the crash -- and in that sense this pull request has value -- but I would prefer to correct the underlying defect rather than masking it.

By the way, your commit has a human name of "Suvrat1629" rather than "Suvrat Acharya". To prevent this in the future, please do one or both of the following:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

NPE: Cannot invoke "javax.lang.model.element.AnnotationMirror.getAnnotationType()" because "annotation" is null

2 participants