Skip to content

Suppresses RLC non-final field overwrite warning for safe constructor field initialization#7050

Open
iamsanjaymalakar wants to merge 93 commits intotypetools:masterfrom
iamsanjaymalakar:7049-dev
Open

Suppresses RLC non-final field overwrite warning for safe constructor field initialization#7050
iamsanjaymalakar wants to merge 93 commits intotypetools:masterfrom
iamsanjaymalakar:7049-dev

Conversation

@iamsanjaymalakar
Copy link
Copy Markdown
Member

@iamsanjaymalakar iamsanjaymalakar commented Apr 18, 2025

Summary by CodeRabbit

  • New Features

    • Enhanced resource leak checker to suppress false-positive warnings when a private field is assigned for the first time within a constructor.
  • Tests

    • Added comprehensive test suite covering various constructor initialization scenarios, including inline initializers, instance initializers, method calls, and conditional branching.

@iamsanjaymalakar iamsanjaymalakar self-assigned this Apr 18, 2025
Copy link
Copy Markdown
Contributor

@kelloggm kelloggm left a comment

Choose a reason for hiding this comment

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

Overall looks good, just a few minor comments. I'd like to take one more look before we merge, though.

@mernst mernst changed the title Suppresses RLC non-final field overwrite warning for safe constructor… #7049 Suppresses RLC non-final field overwrite warning for safe constructor field initialization Apr 18, 2025
@mernst
Copy link
Copy Markdown
Member

mernst commented Apr 18, 2025

@iamsanjaymalakar The typecheck job is not passing.

kelloggm
kelloggm previously approved these changes Jun 6, 2025
Copy link
Copy Markdown
Contributor

@kelloggm kelloggm left a comment

Choose a reason for hiding this comment

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

LGTM, I don't need to review again. Please address these comments and then request a review from Mike.

@mernst
Copy link
Copy Markdown
Member

mernst commented Jul 10, 2025

@iamsanjaymalakar Martin asked you to assign me when you had addressed his comments. Have you addressed them?

@iamsanjaymalakar iamsanjaymalakar assigned mernst and unassigned kelloggm Jul 14, 2025
@iamsanjaymalakar
Copy link
Copy Markdown
Member Author

@iamsanjaymalakar Martin asked you to assign me when you had addressed his comments. Have you addressed them?

Yes, I have. You can take a look.

Copy link
Copy Markdown
Member

@mernst mernst left a comment

Choose a reason for hiding this comment

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

Please clarify some documentation, and update the code if necessary. (I didn't read the code because there is no point in doing so until the documentation is clear.)

@mernst mernst assigned iamsanjaymalakar and unassigned mernst Jul 14, 2025
Copy link
Copy Markdown
Member

@mernst mernst left a comment

Choose a reason for hiding this comment

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

Thanks! This is looking solid. I have a few comments and questions, and then after another round I hope this can be merged.

}
}

/**
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

There are 400 lines of code about finding the first write. Given its size, I suggest abstracting it out into a separate file.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Refactored them into a separate file.

return false;
}
ClassTree classTree = TreePathUtil.enclosingClass(constructorPath);
if (classTree == null) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

When can this happen? Should this be removed, so that the Checker Framework throws an exception when it has an internal defect, rather than silently ignoring the error?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I threw an exception instead of null-check now.

Element lhsElement = TreeUtils.elementFromTree(lhs);
if (targetField == lhsElement) {
isInitialized.set(true);
return null;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Once isInitialized is set to true, there is no need to continue the visitor's traversal. So, use a visitor that permits early exit (short-circuiting).
Every visitor that can return early should use such an optimization.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Thanks for pointing it out, I've added the short-circuiting logic.


/**
* Scans {@code stmts} in source order to determine whether {@code targetAssignment} is definitely
* the first write to {@code targetField} in this constructor fragment.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It could also be in an initializer block, right?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

No, it's only for constructor-body statements. I've clarified in the javadoc.

* exceptional path).
*
* @param tryTree the try statement to inspect
* @param targetField the field to check for assignments
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think it must be of reference (non-primitive) type. Is that correct?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Yes.


/**
* Visitor that determines whether a given assignment in a constructor is definitely the first
* write to its field before any earlier assignment or side-effecting call. The entry point is
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Do "earlier assignments" include static initializer blocks? I know your code handles that, but the comment should say whether this method handles it.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I've updated the comments.

*
* <p>This performs a single AST traversal over the provided tree fragment and is deliberately
* conservative: it does not reason about control flow or path feasibility. It is intended to be
* applied only to supported fragments (expressions and statement subtrees selected by the
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Selected how?
How does the caller know what is legal to pass?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Updated the code comments.

* <p>This performs a single AST traversal over the provided tree fragment and is deliberately
* conservative: it does not reason about control flow or path feasibility. It is intended to be
* applied only to supported fragments (expressions and statement subtrees selected by the
* caller), not to arbitrary statements containing branching/looping constructs.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Consider clarifying whether this code is conservative or unsound if the contract ("only applied to supported fragments") is violated by the caller.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Updated the code comments.

* Scans {@code root} to determine whether {@code targetAssignment} is reached before any
* disqualifying event within this tree fragment.
*
* <p>This method is conservative and AST-only. It returns {@link
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

What does "AST-only" mean in this context?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Updated the code comments.

@mernst mernst assigned iamsanjaymalakar and unassigned mernst Apr 9, 2026
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.

5 participants