Skip to content

Improve inference for generic methods with lambda argument containing return statements#1337

Merged
msridhar merged 29 commits intouber:masterfrom
dhruv-agr:generic-method-lambda-arg-return
Nov 13, 2025
Merged

Improve inference for generic methods with lambda argument containing return statements#1337
msridhar merged 29 commits intouber:masterfrom
dhruv-agr:generic-method-lambda-arg-return

Conversation

@dhruv-agr
Copy link
Copy Markdown
Contributor

@dhruv-agr dhruv-agr commented Nov 9, 2025

This is a follow up to #1312
While generating constraints for params in generateConstraintsForParam, if argument is a lambda expression, then generate constraints for the return expression inside lambda and the functional interface method return type. If the return expression is a method invocation then recursively call generateConstraintsForCall

Summary by CodeRabbit

  • Bug Fixes

    • Improved null-safety checks for lambdas used with generic methods in JSpecify mode by using more accurate inferred lambda return types, reducing false diagnostics about returning nullable values.
  • Tests

    • Expanded and re-enabled tests to validate lambda return-type inference with generic method calls and updated expectations to reflect corrected behavior.

@codecov
Copy link
Copy Markdown

codecov bot commented Nov 9, 2025

Codecov Report

❌ Patch coverage is 85.41667% with 7 lines in your changes missing coverage. Please review.
✅ Project coverage is 88.40%. Comparing base (3b9d78f) to head (d188493).
⚠️ Report is 1 commits behind head on master.

Files with missing lines Patch % Lines
...ava/com/uber/nullaway/generics/GenericsChecks.java 83.72% 4 Missing and 3 partials ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##             master    #1337      +/-   ##
============================================
- Coverage     88.41%   88.40%   -0.01%     
- Complexity     2574     2578       +4     
============================================
  Files            97       97              
  Lines          8618     8654      +36     
  Branches       1713     1719       +6     
============================================
+ Hits           7620     7651      +31     
- Misses          501      504       +3     
- Partials        497      499       +2     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Nov 10, 2025

Walkthrough

The PR adds lambda-aware generic-method inference and propagates inferred lambda return types into NullAway's generic return nullness checks. GenericsChecks gains a pseudo-assignment-based inference path that handles lambdas (including a ReturnFinder to collect return expressions) and refines argument types via dataflow; NullAway.java now prefers genericsChecks.getInferredLambdaType(lambdaTree) when computing generic return-type nullness. Tests in GenericMethodTests were updated to exercise lambda-return inference and related expectations.

Possibly related PRs

  • #1312 — Adds storage/propagation of inferred lambda return types and touches the same generics inference and NullAway call sites for lambda-aware inference.
  • #1256 — Converts GenericsChecks API from static to instance methods and reorganizes generics logic, providing the infrastructure this change builds on.
  • #1286 — Modifies generics inference in GenericsChecks and wires inferred lambda return types through NullAway, overlapping the same code paths.

Suggested reviewers

  • lazaroclapp
  • yuxincs

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.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
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: improving inference for generic methods when a lambda argument contains return statements, which is the core focus of the PR modifications.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 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 ae49fc9 and d188493.

📒 Files selected for processing (1)
  • nullaway/src/main/java/com/uber/nullaway/generics/GenericsChecks.java (4 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: msridhar
Repo: uber/NullAway PR: 1248
File: nullaway/src/main/java/com/uber/nullaway/generics/GenericsChecks.java:847-857
Timestamp: 2025-08-28T04:54:20.953Z
Learning: In NullAway's GenericsChecks.java, NewClassTree support for explicit type argument substitution requires more extensive changes beyond just modifying the conditional in compareGenericTypeParameterNullabilityForCall. The maintainers prefer to handle NewClassTree support in a separate follow-up rather than expanding the scope of PRs focused on specific issues like super constructor calls.
📚 Learning: 2025-08-28T04:54:20.953Z
Learnt from: msridhar
Repo: uber/NullAway PR: 1248
File: nullaway/src/main/java/com/uber/nullaway/generics/GenericsChecks.java:847-857
Timestamp: 2025-08-28T04:54:20.953Z
Learning: In NullAway's GenericsChecks.java, NewClassTree support for explicit type argument substitution requires more extensive changes beyond just modifying the conditional in compareGenericTypeParameterNullabilityForCall. The maintainers prefer to handle NewClassTree support in a separate follow-up rather than expanding the scope of PRs focused on specific issues like super constructor calls.

Applied to files:

  • nullaway/src/main/java/com/uber/nullaway/generics/GenericsChecks.java
🧬 Code graph analysis (1)
nullaway/src/main/java/com/uber/nullaway/generics/GenericsChecks.java (2)
nullaway/src/main/java/com/uber/nullaway/NullabilityUtil.java (1)
  • NullabilityUtil (66-668)
nullaway/src/main/java/com/uber/nullaway/generics/TypeSubstitutionUtils.java (1)
  • TypeSubstitutionUtils (23-312)
🔇 Additional comments (5)
nullaway/src/main/java/com/uber/nullaway/generics/GenericsChecks.java (5)

14-14: LGTM! Necessary imports for lambda analysis.

The new imports BlockTree and TreeScanner are required for analyzing lambda bodies and finding return statements respectively.

Also applies to: 31-31


757-764: LGTM! Clean unification of constraint generation.

The refactoring successfully unifies parameter-passing and return-expression constraint generation into a single method, addressing the previous review feedback about code duplication.


767-812: Excellent unification of pseudo-assignment constraint generation!

This method successfully consolidates the logic for both parameter passing and return expressions, addressing previous review feedback. The implementation correctly:

  • Strips parentheses early to handle wrapped expressions
  • Recursively processes nested generic method calls
  • Refines types using dataflow analysis when applicable
  • Delegates lambda handling to a focused helper method

The comprehensive Javadoc clearly documents the method's purpose, parameters, and side effects.


814-866: Well-designed lambda inference implementation!

This method correctly handles lambda arguments in generic method inference by:

  • Computing the functional interface return type with proper type variable substitution from the enclosing generic method's type parameters (lines 842-845)
  • Processing both expression-bodied and block-bodied lambdas
  • Recursively generating constraints for return expressions, enabling nested generic call inference
  • Reusing the unified generateConstraintsForPseudoAssignment for consistency

The comprehensive Javadoc documents the method's purpose, algorithm, and all parameters including side effects.


868-935: Excellent utility class with proper scope boundaries!

The ReturnFinder class is well-designed with:

  • Clear, comprehensive Javadoc explaining its shallow traversal behavior (lines 868-882)
  • Correct traversal guards that prevent descending into nested lambdas, classes, and methods, ensuring only returns from the current scope are collected
  • Proper handling of void returns via the null check (line 929)
  • Clean static factory method providing a simple API

The implementation correctly ensures that return expressions from nested scopes (which have different type contexts) are not incorrectly included in the analysis.


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.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
nullaway/src/main/java/com/uber/nullaway/generics/GenericsChecks.java (1)

855-907: ReturnFinder is fine; consider parentheses-insensitivity upstream (addressed in prior patch).

No changes needed here if callers strip parentheses before checks, as proposed.

nullaway/src/test/java/com/uber/nullaway/jspecify/GenericMethodTests.java (1)

1008-1035: Add an expression-bodied lambda variant to cover the missed recursion path.

This will catch cases like () -> genericMethod(null) that currently aren’t recursed into.

Suggested addition:

@@
   public void lambdaReturnsGenericMethodCall() {
@@
   }
+
+  @Test
+  public void lambdaReturnsGenericMethodCall_exprBody() {
+    makeHelperWithInferenceFailureWarning()
+        .addSourceLines(
+            "Test.java",
+            "import org.jspecify.annotations.*;",
+            "@NullMarked",
+            "class Test {",
+            "  static interface Supplier<T extends @Nullable Object> { T get(); }",
+            "  static <R extends @Nullable Object> R invokeWithReturn(Supplier<R> supplier) {",
+            "    return supplier.get();",
+            "  }",
+            "  static <U extends @Nullable Object> U genericMethod(U var){ return var; }",
+            "  static void test() {",
+            "    Object x = invokeWithReturn(() -> genericMethod(\"value\"));",
+            "    Object y = invokeWithReturn(() -> genericMethod(null));",
+            "    x.hashCode();",
+            "    // BUG: Diagnostic contains: dereferenced expression y is @Nullable",
+            "    y.hashCode();",
+            "  }",
+            "}")
+        .doTest();
+  }
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 85ac16d and 59959e9.

📒 Files selected for processing (3)
  • nullaway/src/main/java/com/uber/nullaway/NullAway.java (1 hunks)
  • nullaway/src/main/java/com/uber/nullaway/generics/GenericsChecks.java (3 hunks)
  • nullaway/src/test/java/com/uber/nullaway/jspecify/GenericMethodTests.java (2 hunks)
🧰 Additional context used
🧠 Learnings (5)
📓 Common learnings
Learnt from: msridhar
Repo: uber/NullAway PR: 1248
File: nullaway/src/main/java/com/uber/nullaway/generics/GenericsChecks.java:847-857
Timestamp: 2025-08-28T04:54:20.953Z
Learning: In NullAway's GenericsChecks.java, NewClassTree support for explicit type argument substitution requires more extensive changes beyond just modifying the conditional in compareGenericTypeParameterNullabilityForCall. The maintainers prefer to handle NewClassTree support in a separate follow-up rather than expanding the scope of PRs focused on specific issues like super constructor calls.
Learnt from: msridhar
Repo: uber/NullAway PR: 1245
File: guava-recent-unit-tests/src/test/java/com/uber/nullaway/guava/NullAwayGuavaParametricNullnessTests.java:101-102
Timestamp: 2025-08-14T18:50:06.159Z
Learning: In NullAway JSpecify tests, when JDK version requirements exist due to bytecode annotation reading capabilities, prefer failing tests over skipping them on unsupported versions to ensure CI catches regressions and enforces proper JDK version usage for developers.
Learnt from: msridhar
Repo: uber/NullAway PR: 1316
File: jdk-javac-plugin/src/main/java/com/uber/nullaway/javacplugin/NullnessAnnotationSerializer.java:261-293
Timestamp: 2025-10-29T23:56:18.236Z
Learning: In NullAway's jdk-javac-plugin NullnessAnnotationSerializer, type variable bounds with annotations (e.g., `T extends Nullable Object`) are checked at their declaration sites by the typeParamHasAnnotation method for both class-level and method-level type parameters. The hasJSpecifyAnnotationDeep method is designed to check type uses (return types, parameters, etc.) and does not need a TYPEVAR case because type variable declaration bounds are already handled separately.
📚 Learning: 2025-08-28T04:54:20.953Z
Learnt from: msridhar
Repo: uber/NullAway PR: 1248
File: nullaway/src/main/java/com/uber/nullaway/generics/GenericsChecks.java:847-857
Timestamp: 2025-08-28T04:54:20.953Z
Learning: In NullAway's GenericsChecks.java, NewClassTree support for explicit type argument substitution requires more extensive changes beyond just modifying the conditional in compareGenericTypeParameterNullabilityForCall. The maintainers prefer to handle NewClassTree support in a separate follow-up rather than expanding the scope of PRs focused on specific issues like super constructor calls.

Applied to files:

  • nullaway/src/main/java/com/uber/nullaway/generics/GenericsChecks.java
  • nullaway/src/main/java/com/uber/nullaway/NullAway.java
  • nullaway/src/test/java/com/uber/nullaway/jspecify/GenericMethodTests.java
📚 Learning: 2025-08-14T18:50:06.159Z
Learnt from: msridhar
Repo: uber/NullAway PR: 1245
File: guava-recent-unit-tests/src/test/java/com/uber/nullaway/guava/NullAwayGuavaParametricNullnessTests.java:101-102
Timestamp: 2025-08-14T18:50:06.159Z
Learning: In NullAway JSpecify tests, when JDK version requirements exist due to bytecode annotation reading capabilities, prefer failing tests over skipping them on unsupported versions to ensure CI catches regressions and enforces proper JDK version usage for developers.

Applied to files:

  • nullaway/src/main/java/com/uber/nullaway/NullAway.java
  • nullaway/src/test/java/com/uber/nullaway/jspecify/GenericMethodTests.java
📚 Learning: 2025-10-29T23:56:18.236Z
Learnt from: msridhar
Repo: uber/NullAway PR: 1316
File: jdk-javac-plugin/src/main/java/com/uber/nullaway/javacplugin/NullnessAnnotationSerializer.java:261-293
Timestamp: 2025-10-29T23:56:18.236Z
Learning: In NullAway's jdk-javac-plugin NullnessAnnotationSerializer, type variable bounds with annotations (e.g., `T extends Nullable Object`) are checked at their declaration sites by the typeParamHasAnnotation method for both class-level and method-level type parameters. The hasJSpecifyAnnotationDeep method is designed to check type uses (return types, parameters, etc.) and does not need a TYPEVAR case because type variable declaration bounds are already handled separately.

Applied to files:

  • nullaway/src/main/java/com/uber/nullaway/NullAway.java
📚 Learning: 2025-08-29T18:41:43.584Z
Learnt from: msridhar
Repo: uber/NullAway PR: 1259
File: jdk-recent-unit-tests/src/test/java/com/uber/nullaway/jdk17/SwitchTests.java:318-321
Timestamp: 2025-08-29T18:41:43.584Z
Learning: Classes annotated with NullMarked are analyzed by NullAway even if they are not in packages specified by the AnnotatedPackages configuration. The NullMarked annotation guarantees NullAway analysis.

Applied to files:

  • nullaway/src/main/java/com/uber/nullaway/NullAway.java
🧬 Code graph analysis (1)
nullaway/src/main/java/com/uber/nullaway/generics/GenericsChecks.java (2)
nullaway/src/main/java/com/uber/nullaway/NullabilityUtil.java (1)
  • NullabilityUtil (66-668)
nullaway/src/main/java/com/uber/nullaway/generics/TypeSubstitutionUtils.java (1)
  • TypeSubstitutionUtils (23-312)
🔇 Additional comments (3)
nullaway/src/main/java/com/uber/nullaway/NullAway.java (1)

1025-1032: Use inferred lambda type for generic return nullness — LGTM.

Good fallback to the raw lambda type when inference is unavailable; integrates cleanly with GenericsChecks’ cache.

nullaway/src/main/java/com/uber/nullaway/generics/GenericsChecks.java (1)

14-14: Imports for BlockTree and TreeScanner — OK.

Required for lambda body analysis and the ReturnFinder.

Also applies to: 31-31

nullaway/src/test/java/com/uber/nullaway/jspecify/GenericMethodTests.java (1)

989-991: Supplier type parameter rename — OK.

Pure rename; no behavior change.

Copy link
Copy Markdown
Collaborator

@msridhar msridhar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good! A couple more comments

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 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 3e521e5 and 2aad1ad.

📒 Files selected for processing (1)
  • nullaway/src/main/java/com/uber/nullaway/generics/GenericsChecks.java (3 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: msridhar
Repo: uber/NullAway PR: 1248
File: nullaway/src/main/java/com/uber/nullaway/generics/GenericsChecks.java:847-857
Timestamp: 2025-08-28T04:54:20.953Z
Learning: In NullAway's GenericsChecks.java, NewClassTree support for explicit type argument substitution requires more extensive changes beyond just modifying the conditional in compareGenericTypeParameterNullabilityForCall. The maintainers prefer to handle NewClassTree support in a separate follow-up rather than expanding the scope of PRs focused on specific issues like super constructor calls.
Learnt from: msridhar
Repo: uber/NullAway PR: 1245
File: guava-recent-unit-tests/src/test/java/com/uber/nullaway/guava/NullAwayGuavaParametricNullnessTests.java:101-102
Timestamp: 2025-08-14T18:50:06.159Z
Learning: In NullAway JSpecify tests, when JDK version requirements exist due to bytecode annotation reading capabilities, prefer failing tests over skipping them on unsupported versions to ensure CI catches regressions and enforces proper JDK version usage for developers.
Learnt from: msridhar
Repo: uber/NullAway PR: 1316
File: jdk-javac-plugin/src/main/java/com/uber/nullaway/javacplugin/NullnessAnnotationSerializer.java:261-293
Timestamp: 2025-10-29T23:56:18.236Z
Learning: In NullAway's jdk-javac-plugin NullnessAnnotationSerializer, type variable bounds with annotations (e.g., `T extends Nullable Object`) are checked at their declaration sites by the typeParamHasAnnotation method for both class-level and method-level type parameters. The hasJSpecifyAnnotationDeep method is designed to check type uses (return types, parameters, etc.) and does not need a TYPEVAR case because type variable declaration bounds are already handled separately.
📚 Learning: 2025-08-28T04:54:20.953Z
Learnt from: msridhar
Repo: uber/NullAway PR: 1248
File: nullaway/src/main/java/com/uber/nullaway/generics/GenericsChecks.java:847-857
Timestamp: 2025-08-28T04:54:20.953Z
Learning: In NullAway's GenericsChecks.java, NewClassTree support for explicit type argument substitution requires more extensive changes beyond just modifying the conditional in compareGenericTypeParameterNullabilityForCall. The maintainers prefer to handle NewClassTree support in a separate follow-up rather than expanding the scope of PRs focused on specific issues like super constructor calls.

Applied to files:

  • nullaway/src/main/java/com/uber/nullaway/generics/GenericsChecks.java
🧬 Code graph analysis (1)
nullaway/src/main/java/com/uber/nullaway/generics/GenericsChecks.java (2)
nullaway/src/main/java/com/uber/nullaway/NullabilityUtil.java (1)
  • NullabilityUtil (66-668)
nullaway/src/main/java/com/uber/nullaway/generics/TypeSubstitutionUtils.java (1)
  • TypeSubstitutionUtils (23-312)
🔇 Additional comments (1)
nullaway/src/main/java/com/uber/nullaway/generics/GenericsChecks.java (1)

809-883: LGTM! Previous review concerns have been addressed.

The implementation correctly handles both expression-bodied and block-bodied lambdas:

✅ Parentheses are stripped before instanceof checks (lines 830, 857)
✅ Recursive constraint generation is invoked for generic method calls in both lambda forms (lines 831-845 for expressions, 858-872 for blocks)
✅ Functional interface return type constraints are properly established

The logic is sound: lambda inference requires constraining each return expression type against the functional interface return type, and recursively processing nested generic calls within those return expressions.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 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 2aad1ad and 3daee96.

📒 Files selected for processing (1)
  • nullaway/src/main/java/com/uber/nullaway/generics/GenericsChecks.java (3 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: msridhar
Repo: uber/NullAway PR: 1248
File: nullaway/src/main/java/com/uber/nullaway/generics/GenericsChecks.java:847-857
Timestamp: 2025-08-28T04:54:20.953Z
Learning: In NullAway's GenericsChecks.java, NewClassTree support for explicit type argument substitution requires more extensive changes beyond just modifying the conditional in compareGenericTypeParameterNullabilityForCall. The maintainers prefer to handle NewClassTree support in a separate follow-up rather than expanding the scope of PRs focused on specific issues like super constructor calls.
Learnt from: msridhar
Repo: uber/NullAway PR: 1245
File: guava-recent-unit-tests/src/test/java/com/uber/nullaway/guava/NullAwayGuavaParametricNullnessTests.java:101-102
Timestamp: 2025-08-14T18:50:06.159Z
Learning: In NullAway JSpecify tests, when JDK version requirements exist due to bytecode annotation reading capabilities, prefer failing tests over skipping them on unsupported versions to ensure CI catches regressions and enforces proper JDK version usage for developers.
Learnt from: msridhar
Repo: uber/NullAway PR: 1316
File: jdk-javac-plugin/src/main/java/com/uber/nullaway/javacplugin/NullnessAnnotationSerializer.java:261-293
Timestamp: 2025-10-29T23:56:18.236Z
Learning: In NullAway's jdk-javac-plugin NullnessAnnotationSerializer, type variable bounds with annotations (e.g., `T extends Nullable Object`) are checked at their declaration sites by the typeParamHasAnnotation method for both class-level and method-level type parameters. The hasJSpecifyAnnotationDeep method is designed to check type uses (return types, parameters, etc.) and does not need a TYPEVAR case because type variable declaration bounds are already handled separately.
📚 Learning: 2025-08-28T04:54:20.953Z
Learnt from: msridhar
Repo: uber/NullAway PR: 1248
File: nullaway/src/main/java/com/uber/nullaway/generics/GenericsChecks.java:847-857
Timestamp: 2025-08-28T04:54:20.953Z
Learning: In NullAway's GenericsChecks.java, NewClassTree support for explicit type argument substitution requires more extensive changes beyond just modifying the conditional in compareGenericTypeParameterNullabilityForCall. The maintainers prefer to handle NewClassTree support in a separate follow-up rather than expanding the scope of PRs focused on specific issues like super constructor calls.

Applied to files:

  • nullaway/src/main/java/com/uber/nullaway/generics/GenericsChecks.java
🧬 Code graph analysis (1)
nullaway/src/main/java/com/uber/nullaway/generics/GenericsChecks.java (2)
nullaway/src/main/java/com/uber/nullaway/NullabilityUtil.java (1)
  • NullabilityUtil (66-668)
nullaway/src/main/java/com/uber/nullaway/generics/TypeSubstitutionUtils.java (1)
  • TypeSubstitutionUtils (23-312)
🔇 Additional comments (3)
nullaway/src/main/java/com/uber/nullaway/generics/GenericsChecks.java (3)

802-807: LGTM: Lambda argument handling is well-structured.

The new branch properly delegates lambda argument handling to a dedicated method, with a clear comment explaining why lambdas need special treatment for type inference. This integrates cleanly with the existing constraint generation logic.


809-863: Well-designed lambda handling with proper documentation.

This method correctly handles both expression-bodied and block-bodied lambdas, properly obtains the functional interface return type with type variable substitution, and delegates to a shared helper for constraint generation. The Javadoc clearly explains the method's purpose and parameters.


899-966: Excellent utility class with comprehensive documentation.

The ReturnFinder class is well-implemented with:

  • Clear class-level Javadoc explaining its shallow traversal behavior
  • Proper traversal guards preventing descent into nested lambdas, classes, and methods
  • Method-level documentation for the API
  • Correct null-check for void returns

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 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 3daee96 and 08bba59.

📒 Files selected for processing (1)
  • nullaway/src/main/java/com/uber/nullaway/generics/GenericsChecks.java (3 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: msridhar
Repo: uber/NullAway PR: 1248
File: nullaway/src/main/java/com/uber/nullaway/generics/GenericsChecks.java:847-857
Timestamp: 2025-08-28T04:54:20.953Z
Learning: In NullAway's GenericsChecks.java, NewClassTree support for explicit type argument substitution requires more extensive changes beyond just modifying the conditional in compareGenericTypeParameterNullabilityForCall. The maintainers prefer to handle NewClassTree support in a separate follow-up rather than expanding the scope of PRs focused on specific issues like super constructor calls.
Learnt from: msridhar
Repo: uber/NullAway PR: 1245
File: guava-recent-unit-tests/src/test/java/com/uber/nullaway/guava/NullAwayGuavaParametricNullnessTests.java:101-102
Timestamp: 2025-08-14T18:50:06.159Z
Learning: In NullAway JSpecify tests, when JDK version requirements exist due to bytecode annotation reading capabilities, prefer failing tests over skipping them on unsupported versions to ensure CI catches regressions and enforces proper JDK version usage for developers.
Learnt from: msridhar
Repo: uber/NullAway PR: 1316
File: jdk-javac-plugin/src/main/java/com/uber/nullaway/javacplugin/NullnessAnnotationSerializer.java:261-293
Timestamp: 2025-10-29T23:56:18.236Z
Learning: In NullAway's jdk-javac-plugin NullnessAnnotationSerializer, type variable bounds with annotations (e.g., `T extends Nullable Object`) are checked at their declaration sites by the typeParamHasAnnotation method for both class-level and method-level type parameters. The hasJSpecifyAnnotationDeep method is designed to check type uses (return types, parameters, etc.) and does not need a TYPEVAR case because type variable declaration bounds are already handled separately.
📚 Learning: 2025-08-28T04:54:20.953Z
Learnt from: msridhar
Repo: uber/NullAway PR: 1248
File: nullaway/src/main/java/com/uber/nullaway/generics/GenericsChecks.java:847-857
Timestamp: 2025-08-28T04:54:20.953Z
Learning: In NullAway's GenericsChecks.java, NewClassTree support for explicit type argument substitution requires more extensive changes beyond just modifying the conditional in compareGenericTypeParameterNullabilityForCall. The maintainers prefer to handle NewClassTree support in a separate follow-up rather than expanding the scope of PRs focused on specific issues like super constructor calls.

Applied to files:

  • nullaway/src/main/java/com/uber/nullaway/generics/GenericsChecks.java
🧬 Code graph analysis (1)
nullaway/src/main/java/com/uber/nullaway/generics/GenericsChecks.java (2)
nullaway/src/main/java/com/uber/nullaway/NullabilityUtil.java (1)
  • NullabilityUtil (66-668)
nullaway/src/main/java/com/uber/nullaway/generics/TypeSubstitutionUtils.java (1)
  • TypeSubstitutionUtils (23-312)
🔇 Additional comments (4)
nullaway/src/main/java/com/uber/nullaway/generics/GenericsChecks.java (4)

14-14: LGTM: New imports are properly utilized.

Both BlockTree and TreeScanner imports are correctly used in the lambda argument inference implementation.

Also applies to: 31-31


800-805: LGTM: Clean delegation for lambda argument handling.

The new branch correctly identifies lambda arguments and delegates to the specialized handler method.


807-861: LGTM: Well-documented lambda argument handler with proper case handling.

The method has comprehensive Javadoc and correctly handles both expression-bodied and block-bodied lambdas by delegating to a shared helper method, eliminating code duplication.


897-964: LGTM: Well-designed and documented utility class.

The ReturnFinder class has excellent documentation explaining its shallow traversal behavior, and the implementation correctly uses traversal guards to avoid descending into nested scopes. The null check at line 958 properly handles void return statements.

msridhar and others added 8 commits November 12, 2025 17:24
…1339)

`equals` should always accept a `null` argument. Sadly, to make the
check work for AutoValue-generated code, we had to add abstract `equals`
and `hashCode` methods to the `@AutoValue` classes. Once we can require
JDK 17, we can switch to records and get rid of `AutoValue` and possibly
this problem will go away.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

## Release Notes

* **New Features**
* Added a new error-prone check for detecting equals methods missing
proper nullable annotations on parameters.

* **Dependencies**
  * Updated AutoValue dependency from version 1.10.2 to 1.11.0.

* **Code Quality**
* Enhanced null-safety across the codebase with explicit, nullable-aware
implementations for equality semantics.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This lets us undo some of the boilerplate added in uber#1339 that was
required to please the `EqualsMissingNullable` check
@msridhar msridhar merged commit 6a5e72a into uber:master Nov 13, 2025
15 of 17 checks passed
msridhar added a commit that referenced this pull request Dec 19, 2025
…1375)

Fixes #1373 

This is a follow up to #1337. We now use dataflow analysis to refine the
returned type from a lambda when generating constraints for generic
method inference. This ended up being a rather subtle change due to
cyclic dependencies between the dataflow analysis and the generic
inference. To run dataflow analysis on a lambda, dataflow analysis must
be run on the containing method/lambda/initializer first, to determine
the nullability of variables "captured" from the environment. But, that
dataflow analysis on the containing member may depend on the generic
inference result for the current call.

The key changes are:
* We add a method `GenericsChecks#updateEnvironmentMappingForLambda`
that ensures the environment mapping for a lambda is present before
running dataflow analysis on the lambda. This method detects if dataflow
analysis is already running on the containing member, and if so, creates
an environment mapping using the current state of that analysis using
new APIs (see
`AccessPathNullnessAnalysis#getNullnessInfoBeforeNestedMethodWithAnalysisRunning`).
The method also handles multiple levels of lambda nesting.
* In a few places we update `TreePath`s to contain the relevant lambda.
* We add a method `GenericsChecks#shouldRunDataflowForExpression` to
properly detect when dataflow analysis is useful for an expression, to
avoid running the analysis unnecessarily.

Also, we shift tests related to generic methods and lambdas to a new
test class `GenericMethodLambdaArgTests` to make them easier to find.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Expose dataflow/store state during running analyses to retrieve
nullness info before expressions and nested calls.
* Centralized utility to normalize/unwrap expressions used across the
codebase.

* **Bug Fixes**
* Improved generic-method lambda inference and environment mapping for
nested lambdas; refined when dataflow is applied.

* **Tests**
* Added focused tests for generic-method lambda inference and
updated/removed older tests to reflect new behavior.

<sub>✏️ Tip: You can customize this high-level summary in your review
settings.</sub>
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
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.

2 participants