Skip to content

Conversation

@rishikraj990
Copy link
Contributor

@rishikraj990 rishikraj990 commented Dec 29, 2025

A description about what and why you are contributing: Migrate AutoValue to Java Records and for some place direct replacement as there are some strict guidelines to use Records

The issue number: #1400

Fixes #1400

Summary by CodeRabbit

  • Chores

    • Modernized several internal data types to Java records and simplified construction patterns for maintainability.
    • Removed some annotation-processor libraries and bumped static-analysis tool versions.
  • Tests

    • Consolidated test sources by inlining test cases and removed separate test-data files.
  • Behavior

    • Static-analysis warnings for generated code may now be reported where they were previously suppressed.

✏️ Tip: You can customize this high-level summary in your review settings.

@CLAassistant
Copy link

CLAassistant commented Dec 29, 2025

CLA assistant check
All committers have signed the CLA.

@rishikraj990 rishikraj990 marked this pull request as ready for review December 29, 2025 14:25
@rishikraj990
Copy link
Contributor Author

Hi @msridhar,
Could you please review the PR

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 29, 2025

Walkthrough

This PR removes AutoValue usages and dependency entries, converts multiple AutoValue-backed types to Java records or explicit classes (e.g., MethodAnnotationsRecord, MethodClassAndName, FieldRef, FieldInitEntities, CfgParams, AnalysisParams, CollectRecordAndInnerMethod, CollectLikeMethodRecord), updates factory methods and call sites accordingly, removes auto-value entries from the Gradle version catalog and bumps Error Prone versions, re-enables ErrorProne warnings for generated code by deleting the suppression, and inlines contract test sources while deleting the former testdata files.

Possibly related PRs

Suggested reviewers

  • yuxincs
🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 52.38% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Migrate AutoValue to Records' directly and clearly summarizes the main objective of the pull request, which is to replace AutoValue with Java Records throughout the codebase.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

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
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: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
nullaway/src/main/java/com/uber/nullaway/NullAway.java (1)

2819-2878: FieldInitEntities record correctly replaces the AutoValue holder

The FieldInitEntities record mirrors the old AutoValue structure and continues to provide all the accessors relied on by the initialization logic (nonnullInstanceFields(), constructors(), initializer methods/blocks, etc.). Using the create(...) factory to defensively copy into Immutable* collections maintains the previous immutability guarantees.

You might consider trimming the “Generates by Record” text and the inline method-signature commentary in the Javadoc in favor of a shorter description of each component, but that’s stylistic and not blocking.

nullaway/src/main/java/com/uber/nullaway/dataflow/DataFlow.java (1)

92-105: CfgParams must override equals/hashCode for cfgCache to work correctly

CfgParams is used as the key type for cfgCache, but the manual implementation lacks equals / hashCode overrides. Each call to CfgParams.create(path, env) produces a fresh instance with different identity, so cache lookups always use Object's identity-based equality and always miss. This prevents CFG reuse and causes unnecessary recomputation—a significant performance regression from the previous @AutoValue implementation, which generated value-based equality on the codePath field.

The commented placeholder at lines 380-387 indicates this was recognized as incomplete work. Restore value-based semantics by overriding these methods based on codePath and environment, or simplify by making environment a final constructor parameter. Either approach will restore cache hits and eliminate the performance regression.

📜 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 8dd292f and 21d6359.

📒 Files selected for processing (11)
  • build.gradle
  • gradle/libs.versions.toml
  • library-model/library-model-generator/build.gradle
  • library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/MethodAnnotationsRecord.java
  • nullaway/build.gradle
  • nullaway/src/main/java/com/uber/nullaway/ErrorProneCLIFlagsConfig.java
  • nullaway/src/main/java/com/uber/nullaway/LibraryModels.java
  • nullaway/src/main/java/com/uber/nullaway/NullAway.java
  • nullaway/src/main/java/com/uber/nullaway/dataflow/DataFlow.java
  • nullaway/src/main/java/com/uber/nullaway/handlers/StreamNullabilityPropagator.java
  • nullaway/src/main/java/com/uber/nullaway/handlers/stream/CollectLikeMethodRecord.java
💤 Files with no reviewable changes (3)
  • nullaway/build.gradle
  • gradle/libs.versions.toml
  • library-model/library-model-generator/build.gradle
🧰 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/handlers/StreamNullabilityPropagator.java
🔇 Additional comments (3)
build.gradle (1)

87-88: Comment update correctly reflects AutoValue removal

The updated comment drops the AutoValue-specific mention and stays accurate given the migration; no behavioral impact.

nullaway/src/main/java/com/uber/nullaway/dataflow/DataFlow.java (1)

390-395: AnalysisParams record migration is consistent with prior AutoValue usage

Switching AnalysisParams to a record with (ForwardTransferFunction<?, ?> transferFunction, ControlFlowGraph cfg) and keeping the create(...) factory is a straightforward replacement for the AutoValue version. It preserves the previous key semantics for analysisCache (value-based on transfer function and CFG reference), so no additional changes seem necessary here.

nullaway/src/main/java/com/uber/nullaway/LibraryModels.java (1)

328-333: FieldRef record keeps previous value semantics

Converting FieldRef to a record with enclosingClassName and fieldName and updating the factory to call the canonical constructor is behaviorally equivalent to the old AutoValue-based holder. Equality and hashing over both components remain correct for its use in ImmutableSet<FieldRef> and related collections.

Comment on lines 611 to 616
record MethodClassAndName(String enclosingClass,
String methodName) {

static MethodClassAndName create(String enclosingClass, String methodName) {
return new AutoValue_ErrorProneCLIFlagsConfig_MethodClassAndName(enclosingClass, methodName);
return new MethodClassAndName(enclosingClass, methodName);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

MethodClassAndName record migration preserves value semantics

Using a record here keeps the previous AutoValue-style value semantics (field-based equals/hashCode) and works cleanly with the knownInitializers ImmutableSet. The factory and fromClassDotMethod logic remain unchanged in behavior.

If this type is only used inside ErrorProneCLIFlagsConfig, you could optionally mark the record private to keep the helper out of the public surface, but that's non-blocking.

🤖 Prompt for AI Agents
In nullaway/src/main/java/com/uber/nullaway/ErrorProneCLIFlagsConfig.java around
lines 611 to 616, the new MethodClassAndName record preserves value semantics
but should be made private if it’s only used inside ErrorProneCLIFlagsConfig;
change the declaration to a private record MethodClassAndName(...) and keep the
existing static factory and fromClassDotMethod logic unchanged so behavior
remains the same.

Comment on lines 130 to 137
record CollectRecordAndInnerMethod(CollectLikeMethodRecord collectlikeMethodRecord,
Tree innerMethodOrLambda) {

static CollectRecordAndInnerMethod create(
CollectLikeMethodRecord collectlikeMethodRecord, Tree innerMethodOrLambda) {
return new AutoValue_StreamNullabilityPropagator_CollectRecordAndInnerMethod(
return new CollectRecordAndInnerMethod(
collectlikeMethodRecord, innerMethodOrLambda);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

CollectRecordAndInnerMethod record is a clean AutoValue replacement

The record-based CollectRecordAndInnerMethod plus the updated call sites using collectlikeMethodRecord() / innerMethodOrLambda() keep the previous semantics (immutable pair, correct equals/hashCode) while simplifying the implementation. No functional issues spotted.

Optionally, consider renaming the component to collectLikeMethodRecord for readability and consistency with the CollectLikeMethodRecord type name.

Also applies to: 375-382

🤖 Prompt for AI Agents
In
nullaway/src/main/java/com/uber/nullaway/handlers/StreamNullabilityPropagator.java
around lines 130-137 (and similarly 375-382), the record components use names
`collectlikeMethodRecord` and `innerMethodOrLambda`; rename the first component
to `collectLikeMethodRecord` to match the `CollectLikeMethodRecord` type and
improve readability, update the record constructor/factory and all call sites to
use the new accessor `collectLikeMethodRecord()` (and leave
`innerMethodOrLambda()` as-is), and ensure imports and usages compile after the
rename.

Copy link
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.

Thanks for this great contribution! I have some initial comments

build.gradle Outdated
options.errorprone {
// disable warnings in generated code; AutoValue code fails UnnecessaryParentheses check
// disable warnings in generated code; fails UnnecessaryParentheses check
disableWarningsInGeneratedCode = true
Copy link
Collaborator

Choose a reason for hiding this comment

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

Probably we can just get rid of this line now?

Comment on lines 380 to 387
/*
* If needed, need to override these methods
* @Override
* public boolean equals(Object o) { ...codePath... }
*
* @Override
* public int hashCode() { ...codePath... }
*/
Copy link
Collaborator

Choose a reason for hiding this comment

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

Yes, important to override these and only use the codePath field. Also can we override toString?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done


/**
/*
* Generate by Record
Copy link
Collaborator

Choose a reason for hiding this comment

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

Again, these docs should appear as Javadoc for the record parameters

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

@msridhar
Copy link
Collaborator

msridhar commented Jan 1, 2026

@rishikraj990 let me know if you need further help / feedback here

@rishikraj990
Copy link
Contributor Author

will update with accommodating all the suggested changes :)

Copy link
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

♻️ Duplicate comments (2)
nullaway/src/main/java/com/uber/nullaway/handlers/stream/CollectLikeMethodRecord.java (1)

28-42: Move parameter documentation to record Javadoc.

The @param documentation in the create() method should be moved to the record declaration itself using @param tags in the record's Javadoc. This is the standard way to document record components and ensures the documentation appears for all accessors.

🔎 Suggested Javadoc format
 /**
  * An immutable model describing a collect-like method from a stream-based API,
  * such as {@link java.util.stream.Stream#collect(Collector)}.
  *
  * <p>Collect-like methods are distinguished from map-like methods in that they
  * accept a {@link Collector} instance as an argument. This record captures the
  * metadata necessary to identify such methods, match specific collector factory
  * methods, and track how stream elements flow into those factories.
+ *
+ * @param collectorFactoryMethodClass The fully qualified name of the class that contains the collector factory method
+ * @param collectorFactoryMethodSignature The signature of the factory method that creates the {@link Collector} instance
+ * @param argsToCollectorFactoryMethod The indices of the arguments to the collector factory method that are lambdas
+ * @param innerMethodName Name of the method that gets passed the elements of the stream
+ * @param argsFromStream Argument indices to which stream elements are directly passed
  */
nullaway/src/main/java/com/uber/nullaway/NullAway.java (1)

2784-2801: Move parameter documentation to record Javadoc.

The @param documentation should be added to the record declaration's Javadoc rather than (or in addition to) the create() factory method. This ensures documentation appears for the record component accessors.

🔎 Suggested Javadoc format
 /**
  * Aggregates all entities involved in field initialization for a class.
  *
  * <p>This record captures information needed to reason about initialization of
  * {@code @NonNull} fields, including initializer blocks, constructors, and
  * initializer methods, both instance-level and static.
  *
  * <p>The data is extracted from a class symbol and used during NullAway analysis
  * to verify that all required fields are properly initialized.
+ *
+ * @param classSymbol symbol for class
+ * @param nonnullInstanceFields {@code @NonNull} instance fields not directly initialized at declaration
+ * @param nonnullStaticFields {@code @NonNull} static fields not directly initialized at declaration
+ * @param instanceInitializerBlocks instance initializer blocks in declaration order
+ * @param staticInitializerBlocks static initializer blocks in declaration order
+ * @param constructors constructors in the class
+ * @param instanceInitializerMethods non-static initializer methods
+ * @param staticInitializerMethods static initializer methods
  */
📜 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 3000a24 and f8671ff.

📒 Files selected for processing (4)
  • library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/MethodAnnotationsRecord.java
  • nullaway/src/main/java/com/uber/nullaway/NullAway.java
  • nullaway/src/main/java/com/uber/nullaway/dataflow/DataFlow.java
  • nullaway/src/main/java/com/uber/nullaway/handlers/stream/CollectLikeMethodRecord.java
🔇 Additional comments (5)
library-model/library-model-generator/src/main/java/com/uber/nullaway/libmodel/MethodAnnotationsRecord.java (1)

9-11: Excellent migration from AutoValue to Record.

The record declaration is well-formed with all components using Guava immutable types, ensuring proper immutability. The record automatically provides accessors, equals(), hashCode(), and toString(), matching AutoValue's behavior.

nullaway/src/main/java/com/uber/nullaway/handlers/stream/CollectLikeMethodRecord.java (1)

61-73: LGTM!

The factory method correctly delegates to the record constructor, maintaining API compatibility with existing callers.

nullaway/src/main/java/com/uber/nullaway/dataflow/DataFlow.java (2)

354-476: LGTM! Well-designed manual class for cache key semantics.

The CfgParams class correctly excludes environment from equals/hashCode/toString since it's not part of the logical identity. The thorough Javadoc clearly explains why this design was chosen over a record.


478-485: LGTM!

The AnalysisParams record migration is correct. The private create() factory method maintains the existing internal API.

nullaway/src/main/java/com/uber/nullaway/NullAway.java (1)

2822-2840: LGTM!

The create() factory method correctly converts mutable collection inputs (Set, List) to their immutable counterparts (ImmutableSet, ImmutableList), ensuring the record's immutability guarantees are preserved.

@rishikraj990 rishikraj990 requested a review from msridhar January 3, 2026 20:00
@msridhar
Copy link
Collaborator

msridhar commented Jan 3, 2026

@rishikraj990 your changes are failing CI due to formatting and other issues. For the formatting issues you can run ./gradlew spotlessApply to fix. Could you check that ./gradlew build passes before requesting another review? At the least, check that ./gradlew :nullaway:build passes. (./gradlew build passing requires installing an Android SDK.) Thanks!

Copy link
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.

Changes look good but we need CI to pass

@msridhar
Copy link
Collaborator

msridhar commented Jan 6, 2026

@rishikraj990 do you know when you might be able to finish this one up? Also, if you check the box to allow contributions from committers, then we could do some of the easier cleanup. Right now I cannot push to your branch.

Copy link
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: 2

🤖 Fix all issues with AI agents
In @nullaway/src/main/java/com/uber/nullaway/dataflow/DataFlow.java:
- Around line 479-486: The AnalysisParams.record defines a redundant static
factory create() that only delegates to the record constructor; remove the
create(ForwardTransferFunction<?, ?>, ControlFlowGraph) method and update all
call sites that use AnalysisParams.create(...) to use the record constructor
directly (new AnalysisParams(transferFunction, cfg)) or the canonical record
construction form with the same parameters, ensuring you update references in
the code paths that previously called create (e.g., the sites where
transferFunction and cfg are supplied).
- Around line 355-477: Change CfgParams to take ProcessingEnvironment in the
constructor and make the environment field final: replace the single-arg private
CfgParams(TreePath) and the static create(TreePath, ProcessingEnvironment)
factory with a constructor CfgParams(TreePath, ProcessingEnvironment) that
assigns both final fields, update environment() to return the final field as
before, and remove the post-construction mutation paths (and calls to create) so
callers (e.g., code that calls CfgParams.create(...) before passing to the cache
load) instead call new CfgParams(codePath, environment); keep
equals/hashCode/toString based only on codePath.
📜 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 fa305c1 and 91f0cdc.

📒 Files selected for processing (2)
  • gradle/libs.versions.toml
  • nullaway/src/main/java/com/uber/nullaway/dataflow/DataFlow.java
💤 Files with no reviewable changes (1)
  • gradle/libs.versions.toml
🔇 Additional comments (1)
nullaway/src/main/java/com/uber/nullaway/dataflow/DataFlow.java (1)

355-486: Migration from AutoValue to Records/manual classes is well-executed.

The conversion strategy is appropriate:

  • AnalysisParams → Java record (simple value type)
  • CfgParams → manual class (needed to exclude environment from equality/hashing)

This aligns with the PR's objective to migrate away from AutoValue while respecting the constraints of Java records. The use of a manual class for CfgParams correctly handles the requirement that environment should not contribute to cache key equality while still being accessible for CFG construction.

Comment on lines 355 to 477
static final class CfgParams {

/**
* The {@link TreePath} representing the code location for which CFG-related
* parameters are being computed.
*
* <p>This field defines the logical identity of {@code CfgParams}. Equality,
* hash code computation, and string representation are all based solely on
* this field.
*/
private final TreePath codePath;

/**
* The {@link ProcessingEnvironment} associated with the current analysis.
*
* <p>This field is intentionally <em>not</em> final and is excluded from
* {@link #equals(Object)} and {@link #hashCode()} because:
* <ul>
* <li>It is injected after construction</li>
* <li>It is mutable</li>
* <li>It does not contribute to logical identity</li>
* </ul>
*/
private @Nullable ProcessingEnvironment environment;

private static CfgParams create(TreePath codePath, ProcessingEnvironment environment) {
CfgParams cp = new AutoValue_DataFlow_CfgParams(codePath);
/**
* Private constructor used internally to enforce controlled creation via
* {@link #create(TreePath, ProcessingEnvironment)}.
*
* @param codePath the {@link TreePath} identifying the analyzed code location
*/
private CfgParams(TreePath codePath) {
this.codePath = codePath;
}

/**
* Creates a new {@code CfgParams} instance.
*
* <p>The {@link ProcessingEnvironment} is assigned after construction to
* preserve immutability of the identity-defining fields while still allowing
* environment injection.
*
* @param codePath the {@link TreePath} identifying the analyzed code location
* @param environment the {@link ProcessingEnvironment} for the current
* annotation processing round
* @return a fully initialized {@code CfgParams} instance
*/
static CfgParams create(TreePath codePath, ProcessingEnvironment environment) {
CfgParams cp = new CfgParams(codePath);
cp.environment = environment;
return cp;
}

/**
* Returns the {@link ProcessingEnvironment} associated with this instance.
*
* <p>This method guarantees a non-null return value. It is an error to call
* this method before the environment has been set via {@link #create}.
*
* @return the non-null {@link ProcessingEnvironment}
*/
ProcessingEnvironment environment() {
return castToNonNull(environment);
}

abstract TreePath codePath();
/**
* Returns the {@link TreePath} that defines the identity of this instance.
*
* @return the {@link TreePath} associated with this configuration
*/
TreePath codePath() {
return codePath;
}

/**
* Indicates whether some other object is equal to this one.
*
* <p>Equality is based solely on {@link #codePath}. The
* {@link ProcessingEnvironment} is intentionally excluded.
*
* @param o the reference object with which to compare
* @return {@code true} if this object is equal to the given object;
* {@code false} otherwise
*/
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof CfgParams)) {
return false;
}
CfgParams that = (CfgParams) o;
return java.util.Objects.equals(this.codePath, that.codePath);
}

/**
* Returns a hash code value for this object.
*
* <p>The hash code is computed solely from {@link #codePath} to remain
* consistent with {@link #equals(Object)}.
*
* @return a hash code value for this object
*/
@Override
public int hashCode() {
return java.util.Objects.hash(codePath);
}

/**
* Returns a string representation of this object.
*
* <p>The returned string includes only the identity-defining fields and omits
* the {@link ProcessingEnvironment} to keep the output stable and readable.
*
* @return a string representation of this {@code CfgParams}
*/
@Override
public String toString() {
return "CfgParams{codePath=" + codePath + "}";
}

}
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

🧩 Analysis chain

🏁 Script executed:

cd nullaway && find . -name "DataFlow.java" -type f

Repository: uber/NullAway

Length of output: 113


🏁 Script executed:

wc -l nullaway/src/main/java/com/uber/nullaway/dataflow/DataFlow.java

Repository: uber/NullAway

Length of output: 124


🏁 Script executed:

sed -n '355,477p' nullaway/src/main/java/com/uber/nullaway/dataflow/DataFlow.java

Repository: uber/NullAway

Length of output: 4056


🏁 Script executed:

# Check for CfgParams usage throughout the file
rg -n "CfgParams" nullaway/src/main/java/com/uber/nullaway/dataflow/DataFlow.java

Repository: uber/NullAway

Length of output: 1063


🏁 Script executed:

# Check for LoadingCache and synchronization in the file
rg -n "LoadingCache|synchronized|volatile" nullaway/src/main/java/com/uber/nullaway/dataflow/DataFlow.java | head -20

Repository: uber/NullAway

Length of output: 277


🏁 Script executed:

# Check imports to see what caching framework is used
head -50 nullaway/src/main/java/com/uber/nullaway/dataflow/DataFlow.java | grep -E "^import"

Repository: uber/NullAway

Length of output: 1545


🏁 Script executed:

sed -n '93,155p' nullaway/src/main/java/com/uber/nullaway/dataflow/DataFlow.java

Repository: uber/NullAway

Length of output: 3507


🏁 Script executed:

# Check what happens in the CacheLoader.load() method
sed -n '97,155p' nullaway/src/main/java/com/uber/nullaway/dataflow/DataFlow.java

Repository: uber/NullAway

Length of output: 3349


🏁 Script executed:

# Check for all accesses to environment field or environment() method
rg -n "\.environment|environment\(\)" nullaway/src/main/java/com/uber/nullaway/dataflow/DataFlow.java

Repository: uber/NullAway

Length of output: 211


🏁 Script executed:

# Check if CfgParams instances are stored/retrieved outside of immediate cache usage
rg -n "CfgParams" nullaway/src/main/java/com/uber/nullaway/dataflow/DataFlow.java -A 2 -B 2

Repository: uber/NullAway

Length of output: 2940


Simplify CfgParams by initializing environment in the constructor.

The environment field is mutable and non-final, but this is not a practical thread-safety concern here. Each call creates a fresh CfgParams instance that is immediately passed to the cache's load() method, where the environment field is read synchronously. The Guava LoadingCache handles all necessary synchronization internally, and CfgParams instances are never shared across threads.

That said, the post-construction initialization pattern (lines 402-406) adds unnecessary complexity. Passing environment as a constructor parameter would be simpler and clearer without affecting caching behavior, since only codePath contributes to the cache key.

🤖 Prompt for AI Agents
In @nullaway/src/main/java/com/uber/nullaway/dataflow/DataFlow.java around lines
355 - 477, Change CfgParams to take ProcessingEnvironment in the constructor and
make the environment field final: replace the single-arg private
CfgParams(TreePath) and the static create(TreePath, ProcessingEnvironment)
factory with a constructor CfgParams(TreePath, ProcessingEnvironment) that
assigns both final fields, update environment() to return the final field as
before, and remove the post-construction mutation paths (and calls to create) so
callers (e.g., code that calls CfgParams.create(...) before passing to the cache
load) instead call new CfgParams(codePath, environment); keep
equals/hashCode/toString based only on codePath.

Comment on lines 479 to 486
record AnalysisParams(ForwardTransferFunction<?, ?> transferFunction, ControlFlowGraph cfg) {

private static AnalysisParams create(
ForwardTransferFunction<?, ?> transferFunction, ControlFlowGraph cfg) {
AnalysisParams ap = new AutoValue_DataFlow_AnalysisParams(transferFunction, cfg);
return ap;
return new AnalysisParams(transferFunction, cfg);
}

abstract ForwardTransferFunction<?, ?> transferFunction();

abstract ControlFlowGraph cfg();
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Consider removing the redundant factory method.

The create() method simply wraps the record constructor without adding any logic. While it may preserve API compatibility with the previous AutoValue implementation, direct constructor usage is more idiomatic for records.

♻️ Optional: Call-sites can use the record constructor directly

At lines 158 and 350, replace:

-AnalysisParams aparams = AnalysisParams.create(transfer, cfg);
+AnalysisParams aparams = new AnalysisParams(transfer, cfg);

Then remove the create() method entirely:

 record AnalysisParams(ForwardTransferFunction<?, ?> transferFunction, ControlFlowGraph cfg) {
-
-    private static AnalysisParams create(
-        ForwardTransferFunction<?, ?> transferFunction, ControlFlowGraph cfg) {
-      return new AnalysisParams(transferFunction, cfg);
-    }
-
 }
🤖 Prompt for AI Agents
In @nullaway/src/main/java/com/uber/nullaway/dataflow/DataFlow.java around lines
479 - 486, The AnalysisParams.record defines a redundant static factory create()
that only delegates to the record constructor; remove the
create(ForwardTransferFunction<?, ?>, ControlFlowGraph) method and update all
call sites that use AnalysisParams.create(...) to use the record constructor
directly (new AnalysisParams(transferFunction, cfg)) or the canonical record
construction form with the same parameters, ensuring you update references in
the code paths that previously called create (e.g., the sites where
transferFunction and cfg are supplied).

@rishikraj990
Copy link
Contributor Author

Hi @msridhar, apologies for the delayed response. I was traveling over the past week with limited access to my development setup, which caused the slowdown on my side.
I’ve now addressed the formatting issues, updated the Javadocs, and enabled edits from maintainers on the branch. Thanks for pointing that out.
I’ve been trying to resolve the test failures, but I’m currently stuck and could use some guidance. If you have any suggestions or can point me in the right direction, I’d really appreciate the help. https://github.com/uber/NullAway/actions/runs/20873839911/job/59980621844?pr=1415#step:5:547
Thanks again for your patience and for the reviews.

@msridhar
Copy link
Collaborator

@rishikraj990 thanks for the fixes! I think I fixed the test failure in 06ccd25. The JMH NullAway release benchmark runs the current version of NullAway to check the source code of an older release of NullAway. Since that older release still used AutoValue we need to preserve it in the benchmark configuration.

Copy link
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.

Things are looking great, just a couple more minor comments and then I think this will be good to go!

@codecov
Copy link

codecov bot commented Jan 10, 2026

Codecov Report

❌ Patch coverage is 82.14286% with 5 lines in your changes missing coverage. Please review.
✅ Project coverage is 88.39%. Comparing base (2e04fb5) to head (99049cb).
⚠️ Report is 1 commits behind head on master.

Files with missing lines Patch % Lines
...main/java/com/uber/nullaway/dataflow/DataFlow.java 64.28% 3 Missing and 2 partials ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##             master    #1415      +/-   ##
============================================
- Coverage     88.44%   88.39%   -0.05%     
  Complexity     2672     2672              
============================================
  Files            97       97              
  Lines          8852     8861       +9     
  Branches       1772     1774       +2     
============================================
+ Hits           7829     7833       +4     
- Misses          507      510       +3     
- Partials        516      518       +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.

Copy link
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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
nullaway/src/main/java/com/uber/nullaway/NullAway.java (1)

2827-2845: Consider removing the factory method to eliminate redundancy.

The factory method's only call site (lines 2472-2480) already creates immutable copies before passing arguments, making the copyOf() calls in the factory redundant. While ImmutableSet.copyOf() optimizes this case internally, it still adds unnecessary method call overhead.

Since the factory is only used once, consider calling the record's canonical constructor directly at the call site and removing this factory method entirely.

♻️ Proposed refactor to call constructor directly

Remove the factory method and update the call site to use the canonical constructor:

At lines 2472-2480, change:

-    return FieldInitEntities.create(
+    return new FieldInitEntities(
         classSymbol,
         ImmutableSet.copyOf(nonnullInstanceFields),
         ImmutableSet.copyOf(nonnullStaticFields),
         ImmutableList.copyOf(instanceInitializerBlocks),
         ImmutableList.copyOf(staticInitializerBlocks),
         ImmutableSet.copyOf(constructors),
         ImmutableSet.copyOf(instanceInitializerMethods),
         ImmutableSet.copyOf(staticInitializerMethods));

Then remove lines 2821-2845 (the factory method).

🤖 Fix all issues with AI agents
In
@nullaway/src/main/java/com/uber/nullaway/handlers/stream/CollectLikeMethodRecord.java:
- Around line 61-79: The create(...) factory on CollectLikeMethodRecord is a
simple pass-through to the record constructor; update call sites to instantiate
the record directly with new
CollectLikeMethodRecord(collectorFactoryMethodClass,
collectorFactoryMethodSignature, argsToCollectorFactoryMethod, innerMethodName,
argsFromStream) to remove the indirection, then remove or mark the static
create(...) method as deprecated once all usages are migrated; search for usages
of CollectLikeMethodRecord.create and replace them with the direct constructor
call and run tests to ensure no behavioral changes.
📜 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 d85b929 and c2e6bda.

📒 Files selected for processing (2)
  • nullaway/src/main/java/com/uber/nullaway/NullAway.java
  • nullaway/src/main/java/com/uber/nullaway/handlers/stream/CollectLikeMethodRecord.java
🔇 Additional comments (3)
nullaway/src/main/java/com/uber/nullaway/NullAway.java (1)

2811-2846: LGTM! Clean migration from AutoValue to record.

The FieldInitEntities record is well-structured with comprehensive Javadoc. All components use immutable collection types, maintaining type safety and immutability guarantees.

nullaway/src/main/java/com/uber/nullaway/handlers/stream/CollectLikeMethodRecord.java (2)

28-52: LGTM: Excellent documentation.

The Javadoc is comprehensive and well-structured, clearly explaining the purpose of the record and each component. Good use of {@link} references and HTML formatting.


53-59: This suggestion conflicts with NullAway's established patterns. All records in the codebase (MethodAnnotationsRecord, NestedAnnotationInfo, MapLikeMethodRecord, etc.) follow the same convention: no nullability annotations and no validation in constructors. The record is safe in practice because the ImmutableSet fields enforce non-null constraints via Guava's contracts, and records are constructed from controlled internal sources.

Likely an incorrect or invalid review comment.

Comment on lines +61 to 79
/**
* Creates an immutable {@link CollectLikeMethodRecord} instance.
*
* <p>This factory method exists primarily for call-site clarity and symmetry with other model
* types.
*/
public static CollectLikeMethodRecord create(
String collectorFactoryMethodClass,
String collectorFactoryMethodSignature,
ImmutableSet<Integer> argsToCollectorFactoryMethod,
String innerMethodName,
ImmutableSet<Integer> argsFromStream) {
return new AutoValue_CollectLikeMethodRecord(
return new CollectLikeMethodRecord(
collectorFactoryMethodClass,
collectorFactoryMethodSignature,
argsToCollectorFactoryMethod,
innerMethodName,
argsFromStream);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Consider eventual migration to direct constructor usage.

The create() factory method is a pass-through to the record constructor, maintained for call-site clarity and API compatibility during the AutoValue-to-Record migration. While this is acceptable for now, consider eventually migrating call sites to use the record constructor directly (new CollectLikeMethodRecord(...)) to reduce indirection and maintenance overhead.

🤖 Prompt for AI Agents
In
@nullaway/src/main/java/com/uber/nullaway/handlers/stream/CollectLikeMethodRecord.java
around lines 61 - 79, The create(...) factory on CollectLikeMethodRecord is a
simple pass-through to the record constructor; update call sites to instantiate
the record directly with new
CollectLikeMethodRecord(collectorFactoryMethodClass,
collectorFactoryMethodSignature, argsToCollectorFactoryMethod, innerMethodName,
argsFromStream) to remove the indirection, then remove or mark the static
create(...) method as deprecated once all usages are migrated; search for usages
of CollectLikeMethodRecord.create and replace them with the direct constructor
call and run tests to ensure no behavioral changes.

cobayo and others added 4 commits January 12, 2026 16:37
Following up on my previous PR and the goal of issue uber#1425, I have
refactored ContractsTests.java.

- Migrated test data from external files to inline text blocks using
addSourceLines.
- Deleted physical test files: CheckContractPositiveCases.java and
CheckContractNegativeCases.java.
- Removed unnecessary @SuppressWarnings("deprecation") annotations.
- Part of the ongoing effort to modernize tests (uber#1425).

Thank you for contributing to NullAway!

Please note that once you click "Create Pull Request" you will be asked
to sign our [Uber Contributor License
Agreement](https://cla-assistant.io/uber/NullAway) via [CLA
assistant](https://cla-assistant.io/).

Before pressing the "Create Pull Request" button, please provide the
following:

- [x] A description about what and why you are contributing, even if
it's trivial.

- [x] The issue number(s) or PR number(s) in the description if you are
contributing in response to those.

  - [x] If applicable, unit tests.


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

* **Tests**
* Consolidated external test-data into inline test cases within the test
suite for simpler maintenance and clearer test flow.
* Removed separate public test-data classes that previously existed as
external resources.
* Dropped a deprecation-suppression annotation from the public test
class to reflect current warnings handling.

<sub>✏️ Tip: You can customize this high-level summary in your review
settings.</sub>
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
To stay up to date.


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

## Summary by CodeRabbit

* **Chores**
* Updated development dependencies to their latest versions for improved
code quality and analysis capabilities.

<sub>✏️ Tip: You can customize this high-level summary in your review
settings.</sub>

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
@msridhar msridhar enabled auto-merge (squash) January 13, 2026 00:45
@msridhar
Copy link
Collaborator

Went ahead and did the last edits on this one @rishikraj990 . Thanks again for the contribution!!

@msridhar msridhar merged commit c9278a1 into uber:master Jan 13, 2026
9 of 11 checks passed
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.

Switch from using AutoValue to records everywhere

4 participants