Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add @NullUnmarked on classes #134

Merged
merged 47 commits into from
Feb 17, 2023
Merged

Conversation

nimakarimipour
Copy link
Member

This PR enables annotator to add @NullUnmarked annotations to suppress errors inside static initialization blocks.

It will also one last step to resolve any remaining errors after suppression injections by adding @NullUnmarked annotation on the enclosing class.

@nimakarimipour nimakarimipour added the enhancement New feature or request label Feb 11, 2023
@nimakarimipour nimakarimipour self-assigned this Feb 11, 2023
@nimakarimipour nimakarimipour changed the title Add @NullUnmarked for classes Add @NullUnmarked on classes Feb 11, 2023
@nimakarimipour nimakarimipour changed the base branch from master to nimak/resolve-remaining February 11, 2023 19:01
Copy link
Member

@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.

couldn't read through the whole PR but here are a couple quick comments

@@ -263,6 +263,22 @@ private void forceResolveRemainingErrors() {
// Update log.
config.log.updateInjectedAnnotations(nullUnMarkedAnnotations);

// Collect @NullUnmarked annotations for classes for errors in static initialization blocks.
Copy link
Member

Choose a reason for hiding this comment

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

What about instance initialization blocks? E.g., you could have:

class Foo {

  {
    getNullable().toString();
  }

  @Nullable static Object getNullable() { return null; }
}

Will our logic handle this case too?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes it does 🙂. Updated a unit test to verify this 47998c0

Copy link
Member

Choose a reason for hiding this comment

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

Maybe we should do some quick renaming in comments / code where you refer to static blocks, to call them initializer blocks (or just INIT_BLOCK to make it shorter)?

Copy link
Member Author

Choose a reason for hiding this comment

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

Changed to INIT_BLOCK cafef18

Copy link
Collaborator

@lazaroclapp lazaroclapp left a comment

Choose a reason for hiding this comment

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

Some nits and questions, but overall it makes sense to me.

.addInput(
"Super.java",
"package com.uber;",
"import edu.custom.NullUnmarked;",
Copy link
Collaborator

Choose a reason for hiding this comment

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

Does the input need to have the import already or is this added automatically? Or is that outside the scope of this test harness?

Copy link
Member Author

Choose a reason for hiding this comment

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

Actually that was not necessary, removed it 139c19a. Thank you for noticing this.

new AddMarkerAnnotation(
new OnClass("Test.java", "edu.ucr.Test$1"), "edu.custom.NullUnmarked"))
.start();
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

How about named inner classes? Does the logic work in that case?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes it does, please find the added test at 71b998b

@@ -426,6 +427,9 @@ public void staticBlockLocalVariableInitializationTest() {
" }",
"}",
"class B {",
" {",
" foo().hashCode();",
" }",
Copy link
Collaborator

Choose a reason for hiding this comment

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

Do we want to test static initializer block support and instance initializer block in the same test? (if so, the test case might need renaming). Or is it perhaps better to have two separate test cases for ease of reading/debugging?

Copy link
Member Author

Choose a reason for hiding this comment

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

I think the decision for now is to have them in one test until #137 is finalized, therefore I renamed the test name 344007b

Utility.readErrorsFromOutputDirectory(config, config.target, fieldDeclarationStore);
nullUnMarkedAnnotations =
remainingErrors.stream()
.filter(error -> !error.getRegion().isInAnonymousClass())
Copy link
Collaborator

Choose a reason for hiding this comment

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

Not for this PR, but long term, in theory, this should try to find the containing method/initializer and add @NullUnmarked there, no? (For anonymous inner classes). It can get complicated with nested anonymous classes and the places they can appear in, so definitely not asking for that in this PR, just wondering if that's in the roadmap for 1.3.6 or after 1.3.6.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes exactly. But I think the plan is to implement that in after 1.3.6.

FieldDeclarationInfo candidate =
findNodeWithHashHint(node -> node.clazz.equals(clazz), FieldDeclarationInfo.hash(clazz));
if (candidate == null) {
// field is on byte code.
Copy link
Collaborator

Choose a reason for hiding this comment

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

So, this comment (and the name of the class), reference a field, but as far as I can tell this is looking for a class declaration and there is no field involved...

Copy link
Member Author

@nimakarimipour nimakarimipour Feb 15, 2023

Choose a reason for hiding this comment

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

Yes, this class has the required information which its main usage is to store information regarding existing classes and their fields. I have a plan for refactoring these data structures that store information regarding the structure of a code and combine them into one data structure. But the plan is to do that after the release of 1.3.6. Please let me know if you would like me to change it. Thank you.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Ok, that makes sense, but even given that, this comment right above is incorrect here, because this method is not dealing with any fields. Either remove or change the comment?

Copy link
Collaborator

@lazaroclapp lazaroclapp left a comment

Choose a reason for hiding this comment

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

So, mostly good except for a few nits. But one important thing is that I think there is an unrelated change that was added into this PR? Unless I am misunderstanding it. If it's a bug fix, it probably should be on a separate PR, unless it's related to adding @NullUnmarked on classes.

FieldDeclarationInfo candidate =
findNodeWithHashHint(node -> node.clazz.equals(clazz), FieldDeclarationInfo.hash(clazz));
if (candidate == null) {
// field is on byte code.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Ok, that makes sense, but even given that, this comment right above is incorrect here, because this method is not dealing with any fields. Either remove or change the comment?

@@ -92,8 +92,7 @@ public Node(Fix root) {
*/
public void setOrigins(ErrorStore errorStore) {
this.origins =
errorStore.getRegionsForElements(
error -> error.isSingleFix() && error.getResolvingFixes().contains(root));
errorStore.getRegionsForElements(error -> error.getResolvingFixes().contains(root));
Copy link
Collaborator

Choose a reason for hiding this comment

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

Question: what is this change about? I don't understand either what the error.isSingleFix() check was ensuring before, nor why are we removing it now.

Copy link
Member Author

Choose a reason for hiding this comment

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

Origins are set of regions that triggered root fix. The condition isSingleFix was ensuring the error has exactly one fix which is not correct, initialization errors requires multiple fixes to get resolved, therefore I removed this condition.

Copy link
Member Author

Choose a reason for hiding this comment

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

This was fixed in #136 and the change of this PR now changed to branch in #136

// DepA by 3, DepB by 4 and DepC by 2. Hence, the total effect is: 5.
new TReport(new OnMethod("Foo.java", "test.target.Foo", "returnNullableBad(int)"), 5),
// DepA by 3, DepB by 4 and DepC by 3. Hence, the total effect is: 6.
new TReport(new OnMethod("Foo.java", "test.target.Foo", "returnNullableBad(int)"), 6),
Copy link
Collaborator

Choose a reason for hiding this comment

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

What changed that changed the effects here and why is it part of this PR about @NullUnmarked classes? I thought effects were always computed before adding any suppressions/null-unmarked regions... is this related to the other change above I asked about? The error.isSingleFix() check? If so, should that fix be part of this PR?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes the bug fix is in #136 and the base of this PR now changed to branch in #136.

@nimakarimipour nimakarimipour changed the base branch from master to nimak/update-nullaway February 15, 2023 18:45
Base automatically changed from nimak/update-nullaway to master February 16, 2023 01:59
@nimakarimipour
Copy link
Member Author

@lazaroclapp This is ready for another round of review. Thank you very much.

Copy link
Collaborator

@lazaroclapp lazaroclapp left a comment

Choose a reason for hiding this comment

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

LGTM!

@nimakarimipour nimakarimipour merged commit 79bf04f into master Feb 17, 2023
@nimakarimipour nimakarimipour deleted the nimak/nullunmarked-class branch February 17, 2023 22:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants