Skip to content

SONARJAVA-4943 FP on S1144 if private method is referenced by name in annotations#4776

Merged
kaufco merged 5 commits intomasterfrom
marco/SONARJAVA-4943
Apr 22, 2024
Merged

SONARJAVA-4943 FP on S1144 if private method is referenced by name in annotations#4776
kaufco merged 5 commits intomasterfrom
marco/SONARJAVA-4943

Conversation

@kaufco
Copy link
Copy Markdown
Contributor

@kaufco kaufco commented Apr 17, 2024

No description provided.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Nice job! There is just one kinda of a corner case where we would encounter false negatives, other than that the logic looks nice to me!

this.methodNames = methodNames;
}

private Set<String> methodNames;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Using a Set here is not sufficient: if in the same file you have two different classes like so

  @MethodProvided(value = "foo")
  static class TN {
    private void foo() {} // Compliant, method is referenced in annotation
  }
  
  static class FN {
    private void foo() {} // False negative, this method has same name but no references
  }

the CheckAnnotationsForMethodNames will remove the name foo once and for all and the second encounter will not trigger an issue.

Maybe you could use the whole method signature instead of the simple name? Or a different data structure?

Comment on lines +252 to +255
} else if (arg instanceof AssignmentExpressionTree asgn && asgn.expression().is(Tree.Kind.STRING_LITERAL) && (
isMethodAnnotation || isNameIndicatingMethod(((IdentifierTree) asgn.variable()).name())
)) {
removeMethodName((LiteralTree) asgn.expression());
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Not a super strong opinion here, but maybe it could be more comprehensible like

Suggested change
} else if (arg instanceof AssignmentExpressionTree asgn && asgn.expression().is(Tree.Kind.STRING_LITERAL) && (
isMethodAnnotation || isNameIndicatingMethod(((IdentifierTree) asgn.variable()).name())
)) {
removeMethodName((LiteralTree) asgn.expression());
else if (isAnnotationArgumentIndicatingMethod(arg, isMethodAnnotation)) {
removeMethodName((LiteralTree) ((AssignmentExpressionTree)arg).expression());
}

with the logic separated in another boolean method

    private static boolean isAnnotationArgumentIndicatingMethod(ExpressionTree arg, boolean isMethodAnnotation) {
      return arg instanceof AssignmentExpressionTree asgn && asgn.expression().is(Tree.Kind.STRING_LITERAL) && (
        isMethodAnnotation || isNameIndicatingMethod(((IdentifierTree) asgn.variable()).name())
      );
    }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Look good to me! Nice job
Just a couple of comments, but it's up to you

private void reportUnusedPrivateMethods() {
unusedPrivateMethods.stream()
.filter(methodTree -> !unresolvedMethodNames.contains(methodTree.simpleName().name()))
Stream<MethodTree> findUnusedPrivateMethods(ClassTree tree) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Can we make this private static?

this.filteredNames = methodNames;
}

private Set<String> filteredNames;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This could be final

@sonarqube-next
Copy link
Copy Markdown

@kaufco kaufco merged commit 50333fc into master Apr 22, 2024
@kaufco kaufco deleted the marco/SONARJAVA-4943 branch April 22, 2024 10:17
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