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

UnusedMethod: Support additional exempting method annotations #3428

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -45,6 +45,7 @@
import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.errorprone.BugPattern;
import com.google.errorprone.ErrorProneFlags;
import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker.CompilationUnitTreeMatcher;
import com.google.errorprone.fixes.SuggestedFix;
Expand Down Expand Up @@ -97,30 +98,64 @@ public final class UnusedMethod extends BugChecker implements CompilationUnitTre
private static final ImmutableSet<String> EXEMPTING_METHOD_ANNOTATIONS =
ImmutableSet.of(
"com.fasterxml.jackson.annotation.JsonCreator",
"com.fasterxml.jackson.annotation.JsonValue",
"com.google.inject.Provides",
"com.google.inject.Inject",
"com.google.inject.multibindings.ProvidesIntoMap",
"com.google.inject.multibindings.ProvidesIntoSet",
"com.tngtech.java.junit.dataprovider.DataProvider",
"jakarta.annotation.PreDestroy",
"jakarta.annotation.PostConstruct",
"jakarta.inject.Inject",
"jakarta.persistence.PostLoad",
"jakarta.persistence.PostPersist",
"jakarta.persistence.PostRemove",
"jakarta.persistence.PostUpdate",
"jakarta.persistence.PrePersist",
"jakarta.persistence.PreRemove",
"jakarta.persistence.PreUpdate",
"javax.annotation.PreDestroy",
"javax.annotation.PostConstruct",
"javax.inject.Inject",
"javax.persistence.PostLoad",
"javax.persistence.PostPersist",
"javax.persistence.PostRemove",
"javax.persistence.PostUpdate",
"javax.persistence.PrePersist",
"javax.persistence.PreRemove",
"javax.persistence.PreUpdate",
"org.apache.beam.sdk.transforms.DoFn.ProcessElement",
"org.aspectj.lang.annotation.Pointcut",
"org.aspectj.lang.annotation.After",
"org.aspectj.lang.annotation.Before",
"org.springframework.context.annotation.Bean",
"org.testng.annotations.AfterClass",
"org.testng.annotations.AfterMethod",
"org.testng.annotations.BeforeClass",
"org.testng.annotations.BeforeMethod",
"org.testng.annotations.DataProvider",
"org.junit.AfterClass",
"org.junit.BeforeClass");
"org.junit.Test",
"org.junit.jupiter.api.BeforeAll",
"org.junit.jupiter.api.AfterAll",
"org.junit.jupiter.api.AfterEach",
"org.junit.jupiter.api.BeforeEach",
"org.junit.jupiter.api.RepeatedTest",
"org.junit.jupiter.api.Test",
"org.junit.jupiter.params.ParameterizedTest");

/** The set of types exempting a type that is extending or implementing them. */
private static final ImmutableSet<String> EXEMPTING_SUPER_TYPES = ImmutableSet.of();

private final ImmutableSet<String> additionalExemptingMethodAnnotations;

public UnusedMethod(ErrorProneFlags errorProneFlags) {
this.additionalExemptingMethodAnnotations =
errorProneFlags
.getList("UnusedMethod:ExemptingMethodAnnotations")
.map(ImmutableSet::copyOf)
.orElseGet(ImmutableSet::of);
}

@Override
public Description matchCompilationUnit(CompilationUnitTree tree, VisitorState state) {
// Map of symbols to method declarations. Initially this is a map of all of the methods. As we
Expand Down Expand Up @@ -430,14 +465,16 @@ public Void visitMethod(MethodTree tree, Void unused) {
* Looks at the list of {@code annotations} and see if there is any annotation which exists {@code
* exemptingAnnotations}.
*/
private static boolean exemptedByAnnotation(List<? extends AnnotationTree> annotations) {
private boolean exemptedByAnnotation(List<? extends AnnotationTree> annotations) {
for (AnnotationTree annotation : annotations) {
Type annotationType = getType(annotation);
if (annotationType == null) {
continue;
}
TypeSymbol tsym = annotationType.tsym;
if (EXEMPTING_METHOD_ANNOTATIONS.contains(tsym.getQualifiedName().toString())) {
String annotationName = tsym.getQualifiedName().toString();
if (EXEMPTING_METHOD_ANNOTATIONS.contains(annotationName)
|| additionalExemptingMethodAnnotations.contains(annotationName)) {
return true;
}
}
Expand Down
Expand Up @@ -14,6 +14,7 @@

package com.google.errorprone.bugpatterns;

import com.google.common.collect.ImmutableList;
import com.google.errorprone.BugCheckerRefactoringTestHelper;
import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
import com.google.errorprone.CompilationTestHelper;
Expand Down Expand Up @@ -138,6 +139,21 @@ public void exemptedByName() {
.doTest();
}

@Test
public void exemptedByCustomAnnotation() {
helper
.addSourceLines("Foo.java", "package example;", "@interface Foo {}")
.addSourceLines(
"ExemptedByCustomAnnotation.java",
"package example;",
"class ExemptedByCustomAnnotation {",
" @Foo",
" private void bar() {}",
"}")
.setArgs("-XepOpt:UnusedMethod:ExemptingMethodAnnotations=example.Foo")
.doTest();
}

@Test
public void suppressions() {
helper
Expand Down