diff --git a/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/CanonicalClassNameUsage.java b/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/CanonicalClassNameUsage.java new file mode 100644 index 00000000000..6b356103e54 --- /dev/null +++ b/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/CanonicalClassNameUsage.java @@ -0,0 +1,80 @@ +package tech.picnic.errorprone.bugpatterns; + +import static com.google.errorprone.BugPattern.LinkType.CUSTOM; +import static com.google.errorprone.BugPattern.SeverityLevel.WARNING; +import static com.google.errorprone.BugPattern.StandardTags.FRAGILE_CODE; +import static com.google.errorprone.matchers.Matchers.instanceMethod; +import static tech.picnic.errorprone.bugpatterns.util.Documentation.BUG_PATTERNS_BASE_URL; + +import com.google.auto.service.AutoService; +import com.google.errorprone.BugPattern; +import com.google.errorprone.VisitorState; +import com.google.errorprone.annotations.Var; +import com.google.errorprone.bugpatterns.BugChecker; +import com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher; +import com.google.errorprone.fixes.SuggestedFixes; +import com.google.errorprone.matchers.Description; +import com.google.errorprone.matchers.Matcher; +import com.google.errorprone.util.ASTHelpers; +import com.sun.source.tree.BinaryTree; +import com.sun.source.tree.ExpressionTree; +import com.sun.source.tree.MethodInvocationTree; +import com.sun.source.util.TreePath; +import com.sun.tools.javac.code.Symbol.MethodSymbol; +import java.util.regex.Pattern; + +/** + * A {@link BugChecker} that flags invocations of {@link Class#getName()} where {@link + * Class#getCanonicalName()} was likely meant. + * + *

For top-level types these two methods generally return the same result, but for nested types + * the former separates identifiers using a dollar sign ({@code $}) rather than a dot ({@code .}). + */ +// XXX: This check currently doesn't flag `Class::getName` method references. +@AutoService(BugChecker.class) +@BugPattern( + summary = "This code should likely use the type's canonical name", + link = BUG_PATTERNS_BASE_URL + "CanonicalClassNameUsage", + linkType = CUSTOM, + severity = WARNING, + tags = FRAGILE_CODE) +public final class CanonicalClassNameUsage extends BugChecker + implements MethodInvocationTreeMatcher { + private static final long serialVersionUID = 1L; + private static final Matcher GET_NAME_INVOCATION = + instanceMethod().onExactClass(Class.class.getCanonicalName()).named("getName"); + private static final Pattern CANONICAL_NAME_USING_TYPES = + Pattern.compile("(com\\.google\\.errorprone|tech\\.picnic\\.errorprone)\\..*"); + + /** Instantiates a new {@link CanonicalClassNameUsage} instance. */ + public CanonicalClassNameUsage() {} + + @Override + public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) { + if (!GET_NAME_INVOCATION.matches(tree, state) || !isPassedToCanonicalNameUsingType(state)) { + /* + * This is not a `class.getName()` invocation of which the result is passed to another method + * known to accept canonical type names. + */ + return Description.NO_MATCH; + } + + return describeMatch( + tree, SuggestedFixes.renameMethodInvocation(tree, "getCanonicalName", state)); + } + + private static boolean isPassedToCanonicalNameUsingType(VisitorState state) { + @Var TreePath path = state.getPath().getParentPath(); + while (path.getLeaf() instanceof BinaryTree) { + path = path.getParentPath(); + } + + return path.getLeaf() instanceof MethodInvocationTree + && isOwnedByCanonicalNameUsingType( + ASTHelpers.getSymbol((MethodInvocationTree) path.getLeaf())); + } + + private static boolean isOwnedByCanonicalNameUsingType(MethodSymbol symbol) { + return CANONICAL_NAME_USING_TYPES.matcher(symbol.owner.getQualifiedName()).matches(); + } +} diff --git a/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/DirectReturn.java b/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/DirectReturn.java index 212d0b12455..9ed26605e11 100644 --- a/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/DirectReturn.java +++ b/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/DirectReturn.java @@ -58,7 +58,10 @@ public final class DirectReturn extends BugChecker implements BlockTreeMatcher { private static final Matcher VARIABLE_RETURN = returnStatement(isVariable()); private static final Matcher MOCKITO_MOCK_OR_SPY_WITH_IMPLICIT_TYPE = allOf( - not(toType(MethodInvocationTree.class, argument(0, isSameType(Class.class.getName())))), + not( + toType( + MethodInvocationTree.class, + argument(0, isSameType(Class.class.getCanonicalName())))), staticMethod().onClass("org.mockito.Mockito").namedAnyOf("mock", "spy")); /** Instantiates a new {@link DirectReturn} instance. */ diff --git a/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/ExplicitEnumOrdering.java b/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/ExplicitEnumOrdering.java index b04f78073d9..37fb7d60860 100644 --- a/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/ExplicitEnumOrdering.java +++ b/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/ExplicitEnumOrdering.java @@ -44,7 +44,7 @@ public final class ExplicitEnumOrdering extends BugChecker implements MethodInvocationTreeMatcher { private static final long serialVersionUID = 1L; private static final Matcher EXPLICIT_ORDERING = - staticMethod().onClass(Ordering.class.getName()).named("explicit"); + staticMethod().onClass(Ordering.class.getCanonicalName()).named("explicit"); /** Instantiates a new {@link ExplicitEnumOrdering} instance. */ public ExplicitEnumOrdering() {} diff --git a/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/FluxFlatMapUsage.java b/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/FluxFlatMapUsage.java index 16e55d4cdd6..8bd510f3dae 100644 --- a/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/FluxFlatMapUsage.java +++ b/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/FluxFlatMapUsage.java @@ -66,7 +66,7 @@ public final class FluxFlatMapUsage extends BugChecker instanceMethod() .onDescendantOf(FLUX) .namedAnyOf("flatMap", "flatMapSequential") - .withParameters(Function.class.getName()); + .withParameters(Function.class.getCanonicalName()); private static final Supplier FLUX_OF_PUBLISHERS = VisitorState.memoize( generic(FLUX, subOf(generic(type("org.reactivestreams.Publisher"), unbound())))); diff --git a/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/FluxImplicitBlock.java b/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/FluxImplicitBlock.java index 17c8098c09b..7691de3e116 100644 --- a/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/FluxImplicitBlock.java +++ b/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/FluxImplicitBlock.java @@ -48,7 +48,8 @@ public final class FluxImplicitBlock extends BugChecker implements MethodInvocat .onDescendantOf("reactor.core.publisher.Flux") .namedAnyOf("toIterable", "toStream") .withNoParameters(); - private static final Supplier STREAM = Suppliers.typeFromString(Stream.class.getName()); + private static final Supplier STREAM = + Suppliers.typeFromString(Stream.class.getCanonicalName()); /** Instantiates a new {@link FluxImplicitBlock} instance. */ public FluxImplicitBlock() {} diff --git a/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/FormatStringConcatenation.java b/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/FormatStringConcatenation.java index 7ea1f65d450..ce419135015 100644 --- a/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/FormatStringConcatenation.java +++ b/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/FormatStringConcatenation.java @@ -68,7 +68,7 @@ public final class FormatStringConcatenation extends BugChecker anyMethod() .anyClass() .withAnyName() - .withParameters(String.class.getName(), Throwable.class.getName()); + .withParameters(String.class.getCanonicalName(), Throwable.class.getCanonicalName()); // XXX: Drop some of these methods if we use Refaster to replace some with others. private static final Matcher ASSERTJ_FORMAT_METHOD = diff --git a/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/IdentityConversion.java b/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/IdentityConversion.java index fb11dbc86e7..63892793667 100644 --- a/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/IdentityConversion.java +++ b/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/IdentityConversion.java @@ -56,7 +56,7 @@ public final class IdentityConversion extends BugChecker implements MethodInvoca .map(Class::getName) .collect(toImmutableSet())) .named("valueOf"), - staticMethod().onClass(String.class.getName()).named("valueOf"), + staticMethod().onClass(String.class.getCanonicalName()).named("valueOf"), staticMethod() .onClassAny( "com.google.common.collect.ImmutableBiMap", diff --git a/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/JUnitValueSource.java b/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/JUnitValueSource.java index e6fe6df8529..6a786e6ad07 100644 --- a/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/JUnitValueSource.java +++ b/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/JUnitValueSource.java @@ -99,12 +99,12 @@ public final class JUnitValueSource extends BugChecker implements MethodTreeMatc allOf( staticMethod() .onClassAny( - Stream.class.getName(), - IntStream.class.getName(), - LongStream.class.getName(), - DoubleStream.class.getName(), - List.class.getName(), - Set.class.getName(), + Stream.class.getCanonicalName(), + IntStream.class.getCanonicalName(), + LongStream.class.getCanonicalName(), + DoubleStream.class.getCanonicalName(), + List.class.getCanonicalName(), + Set.class.getCanonicalName(), "com.google.common.collect.ImmutableList", "com.google.common.collect.ImmutableSet") .named("of"), diff --git a/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/MockitoMockClassReference.java b/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/MockitoMockClassReference.java index 49f36937d30..f99bba08c94 100644 --- a/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/MockitoMockClassReference.java +++ b/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/MockitoMockClassReference.java @@ -50,7 +50,7 @@ public final class MockitoMockClassReference extends BugChecker private static final long serialVersionUID = 1L; private static final Matcher MOCKITO_MOCK_OR_SPY_WITH_HARDCODED_TYPE = allOf( - argument(0, allOf(isSameType(Class.class.getName()), not(isVariable()))), + argument(0, allOf(isSameType(Class.class.getCanonicalName()), not(isVariable()))), staticMethod().onClass("org.mockito.Mockito").namedAnyOf("mock", "spy")); /** Instantiates a new {@link MockitoMockClassReference} instance. */ diff --git a/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/NonEmptyMono.java b/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/NonEmptyMono.java index 4108d703cb2..79a185b4401 100644 --- a/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/NonEmptyMono.java +++ b/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/NonEmptyMono.java @@ -72,7 +72,7 @@ public final class NonEmptyMono extends BugChecker implements MethodInvocationTr instanceMethod() .onDescendantOf("reactor.core.publisher.Flux") .named("reduce") - .withParameters(Object.class.getName(), BiFunction.class.getName()), + .withParameters(Object.class.getCanonicalName(), BiFunction.class.getCanonicalName()), instanceMethod() .onDescendantOf("reactor.core.publisher.Mono") .namedAnyOf("defaultIfEmpty", "hasElement", "single")); diff --git a/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/PrimitiveComparison.java b/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/PrimitiveComparison.java index 9f2d2f82198..8414d1da569 100644 --- a/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/PrimitiveComparison.java +++ b/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/PrimitiveComparison.java @@ -55,21 +55,21 @@ public final class PrimitiveComparison extends BugChecker implements MethodInvoc private static final Matcher STATIC_COMPARISON_METHOD = anyOf( staticMethod() - .onClass(Comparator.class.getName()) + .onClass(Comparator.class.getCanonicalName()) .namedAnyOf("comparingInt", "comparingLong", "comparingDouble"), staticMethod() - .onClass(Comparator.class.getName()) + .onClass(Comparator.class.getCanonicalName()) .named("comparing") - .withParameters(Function.class.getName())); + .withParameters(Function.class.getCanonicalName())); private static final Matcher INSTANCE_COMPARISON_METHOD = anyOf( instanceMethod() - .onDescendantOf(Comparator.class.getName()) + .onDescendantOf(Comparator.class.getCanonicalName()) .namedAnyOf("thenComparingInt", "thenComparingLong", "thenComparingDouble"), instanceMethod() - .onDescendantOf(Comparator.class.getName()) + .onDescendantOf(Comparator.class.getCanonicalName()) .named("thenComparing") - .withParameters(Function.class.getName())); + .withParameters(Function.class.getCanonicalName())); /** Instantiates a new {@link PrimitiveComparison} instance. */ public PrimitiveComparison() {} @@ -168,7 +168,7 @@ private static Fix suggestFix( switch (expr.getKind()) { case IDENTIFIER: return SuggestedFix.builder() - .addStaticImport(Comparator.class.getName() + '.' + preferredMethodName) + .addStaticImport(Comparator.class.getCanonicalName() + '.' + preferredMethodName) .replace(expr, preferredMethodName) .build(); case MEMBER_SELECT: diff --git a/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/RedundantStringConversion.java b/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/RedundantStringConversion.java index 8ea3f7adb86..201b43eeef3 100644 --- a/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/RedundantStringConversion.java +++ b/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/RedundantStringConversion.java @@ -86,7 +86,7 @@ public final class RedundantStringConversion extends BugChecker private static final Matcher WELL_KNOWN_STRING_CONVERSION_METHODS = anyOf( instanceMethod() - .onDescendantOfAny(Object.class.getName()) + .onDescendantOfAny(Object.class.getCanonicalName()) .named("toString") .withNoParameters(), allOf( @@ -100,7 +100,7 @@ public final class RedundantStringConversion extends BugChecker .collect(toImmutableSet())) .named("toString"), allOf( - staticMethod().onClass(String.class.getName()).named("valueOf"), + staticMethod().onClass(String.class.getCanonicalName()).named("valueOf"), not( anyMethod() .anyClass() @@ -109,27 +109,29 @@ public final class RedundantStringConversion extends BugChecker ImmutableList.of(Suppliers.arrayOf(Suppliers.CHAR_TYPE)))))))); private static final Matcher STRINGBUILDER_APPEND_INVOCATION = instanceMethod() - .onDescendantOf(StringBuilder.class.getName()) + .onDescendantOf(StringBuilder.class.getCanonicalName()) .named("append") - .withParameters(String.class.getName()); + .withParameters(String.class.getCanonicalName()); private static final Matcher STRINGBUILDER_INSERT_INVOCATION = instanceMethod() - .onDescendantOf(StringBuilder.class.getName()) + .onDescendantOf(StringBuilder.class.getCanonicalName()) .named("insert") - .withParameters(int.class.getName(), String.class.getName()); + .withParameters(int.class.getCanonicalName(), String.class.getCanonicalName()); private static final Matcher FORMATTER_INVOCATION = anyOf( - staticMethod().onClass(String.class.getName()).named("format"), - instanceMethod().onDescendantOf(Formatter.class.getName()).named("format"), + staticMethod().onClass(String.class.getCanonicalName()).named("format"), + instanceMethod().onDescendantOf(Formatter.class.getCanonicalName()).named("format"), instanceMethod() - .onDescendantOfAny(PrintStream.class.getName(), PrintWriter.class.getName()) + .onDescendantOfAny( + PrintStream.class.getCanonicalName(), PrintWriter.class.getCanonicalName()) .namedAnyOf("format", "printf"), instanceMethod() - .onDescendantOfAny(PrintStream.class.getName(), PrintWriter.class.getName()) + .onDescendantOfAny( + PrintStream.class.getCanonicalName(), PrintWriter.class.getCanonicalName()) .namedAnyOf("print", "println") - .withParameters(Object.class.getName()), + .withParameters(Object.class.getCanonicalName()), staticMethod() - .onClass(Console.class.getName()) + .onClass(Console.class.getCanonicalName()) .namedAnyOf("format", "printf", "readline", "readPassword")); private static final Matcher GUAVA_GUARD_INVOCATION = anyOf( diff --git a/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/RefasterAnyOfUsage.java b/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/RefasterAnyOfUsage.java index 97e6814644b..96e6bc78c6a 100644 --- a/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/RefasterAnyOfUsage.java +++ b/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/RefasterAnyOfUsage.java @@ -35,7 +35,7 @@ public final class RefasterAnyOfUsage extends BugChecker implements MethodInvocationTreeMatcher { private static final long serialVersionUID = 1L; private static final Matcher REFASTER_ANY_OF = - staticMethod().onClass(Refaster.class.getName()).named("anyOf"); + staticMethod().onClass(Refaster.class.getCanonicalName()).named("anyOf"); /** Instantiates a new {@link RefasterAnyOfUsage} instance. */ public RefasterAnyOfUsage() {} diff --git a/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/StringJoin.java b/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/StringJoin.java index ff520704f33..2e278a4a1f7 100644 --- a/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/StringJoin.java +++ b/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/StringJoin.java @@ -49,7 +49,7 @@ public final class StringJoin extends BugChecker implements MethodInvocationTree private static final long serialVersionUID = 1L; private static final Splitter FORMAT_SPECIFIER_SPLITTER = Splitter.on("%s"); private static final Matcher STRING_FORMAT_INVOCATION = - staticMethod().onClass(String.class.getName()).named("format"); + staticMethod().onClass(String.class.getCanonicalName()).named("format"); private static final Supplier CHAR_SEQUENCE_TYPE = Suppliers.typeFromClass(CharSequence.class); private static final Supplier FORMATTABLE_TYPE = Suppliers.typeFromClass(Formattable.class); diff --git a/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/TimeZoneUsage.java b/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/TimeZoneUsage.java index c4426261ff9..5cdfec6cea6 100644 --- a/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/TimeZoneUsage.java +++ b/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/TimeZoneUsage.java @@ -45,11 +45,11 @@ public final class TimeZoneUsage extends BugChecker implements MethodInvocationT anyOf( allOf( instanceMethod() - .onDescendantOf(Clock.class.getName()) + .onDescendantOf(Clock.class.getCanonicalName()) .namedAnyOf("getZone", "withZone"), not(enclosingClass(isSubtypeOf(Clock.class)))), staticMethod() - .onClass(Clock.class.getName()) + .onClass(Clock.class.getCanonicalName()) .namedAnyOf( "system", "systemDefaultZone", @@ -59,14 +59,17 @@ public final class TimeZoneUsage extends BugChecker implements MethodInvocationT "tickSeconds"), staticMethod() .onClassAny( - LocalDate.class.getName(), - LocalDateTime.class.getName(), - LocalTime.class.getName(), - OffsetDateTime.class.getName(), - OffsetTime.class.getName(), - ZonedDateTime.class.getName()) + LocalDate.class.getCanonicalName(), + LocalDateTime.class.getCanonicalName(), + LocalTime.class.getCanonicalName(), + OffsetDateTime.class.getCanonicalName(), + OffsetTime.class.getCanonicalName(), + ZonedDateTime.class.getCanonicalName()) .named("now"), - staticMethod().onClassAny(Instant.class.getName()).named("now").withNoParameters()); + staticMethod() + .onClassAny(Instant.class.getCanonicalName()) + .named("now") + .withNoParameters()); /** Instantiates a new {@link TimeZoneUsage} instance. */ public TimeZoneUsage() {} diff --git a/error-prone-contrib/src/test/java/tech/picnic/errorprone/bugpatterns/CanonicalClassNameUsageTest.java b/error-prone-contrib/src/test/java/tech/picnic/errorprone/bugpatterns/CanonicalClassNameUsageTest.java new file mode 100644 index 00000000000..b471fd24b46 --- /dev/null +++ b/error-prone-contrib/src/test/java/tech/picnic/errorprone/bugpatterns/CanonicalClassNameUsageTest.java @@ -0,0 +1,81 @@ +package tech.picnic.errorprone.bugpatterns; + +import com.google.errorprone.BugCheckerRefactoringTestHelper; +import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode; +import com.google.errorprone.CompilationTestHelper; +import org.junit.jupiter.api.Test; + +final class CanonicalClassNameUsageTest { + @Test + void identification() { + CompilationTestHelper.newInstance(CanonicalClassNameUsage.class, getClass()) + .setArgs( + "--add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED", + "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED") + .addSourceLines( + "A.java", + "import static com.google.errorprone.matchers.Matchers.instanceMethod;", + "", + "import com.google.errorprone.VisitorState;", + "import tech.picnic.errorprone.bugpatterns.util.MoreTypes;", + "", + "class A {", + " void m(VisitorState state) {", + " String a = A.class.getName();", + " String b = getClass().getName();", + " A.class.getName().toString();", + " System.out.println(A.class.getName());", + " methodInUnnamedPackage(A.class.getName());", + " instanceMethod().onExactClass(A.class.getCanonicalName());", + " MoreTypes.type(A.class.getCanonicalName());", + " MoreTypes.type(A.class.getCanonicalName() + \".SubType\");", + " instanceMethod().onExactClass(methodInUnnamedPackage(A.class.getName()));", + " // BUG: Diagnostic contains:", + " instanceMethod().onExactClass(A.class.getName());", + " // BUG: Diagnostic contains:", + " MoreTypes.type(A.class.getName());", + " // BUG: Diagnostic contains:", + " state.binaryNameFromClassname(A.class.getName() + \".SubType\");", + " }", + "", + " String methodInUnnamedPackage(String str) {", + " return str;", + " }", + "}") + .doTest(); + } + + @Test + void replacement() { + BugCheckerRefactoringTestHelper.newInstance(CanonicalClassNameUsage.class, getClass()) + .addInputLines( + "A.java", + "import static com.google.errorprone.matchers.Matchers.instanceMethod;", + "", + "import com.google.errorprone.BugPattern;", + "import tech.picnic.errorprone.bugpatterns.util.MoreTypes;", + "", + "class A {", + " void m() {", + " instanceMethod().onDescendantOfAny(A.class.getName(), BugPattern.LinkType.class.getName());", + " MoreTypes.type(String.class.getName());", + " }", + "}") + .addOutputLines( + "A.java", + "import static com.google.errorprone.matchers.Matchers.instanceMethod;", + "", + "import com.google.errorprone.BugPattern;", + "import tech.picnic.errorprone.bugpatterns.util.MoreTypes;", + "", + "class A {", + " void m() {", + " instanceMethod()", + " .onDescendantOfAny(", + " A.class.getCanonicalName(), BugPattern.LinkType.class.getCanonicalName());", + " MoreTypes.type(String.class.getCanonicalName());", + " }", + "}") + .doTest(TestMode.TEXT_MATCH); + } +} diff --git a/error-prone-contrib/src/test/java/tech/picnic/errorprone/bugpatterns/util/MoreMatchersTest.java b/error-prone-contrib/src/test/java/tech/picnic/errorprone/bugpatterns/util/MoreMatchersTest.java index faed5900f37..b299ff20eb4 100644 --- a/error-prone-contrib/src/test/java/tech/picnic/errorprone/bugpatterns/util/MoreMatchersTest.java +++ b/error-prone-contrib/src/test/java/tech/picnic/errorprone/bugpatterns/util/MoreMatchersTest.java @@ -125,7 +125,9 @@ public static final class IsSubTypeOfTestChecker extends BugChecker private static final long serialVersionUID = 1L; private static final Matcher DELEGATE = MoreMatchers.isSubTypeOf( - generic(type(ImmutableSet.class.getName()), subOf(type(Number.class.getName())))); + generic( + type(ImmutableSet.class.getCanonicalName()), + subOf(type(Number.class.getCanonicalName())))); @Override public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) { diff --git a/refaster-support/src/main/java/tech/picnic/errorprone/refaster/matchers/IsEmpty.java b/refaster-support/src/main/java/tech/picnic/errorprone/refaster/matchers/IsEmpty.java index bbe9ee104ec..fb0c77b7484 100644 --- a/refaster-support/src/main/java/tech/picnic/errorprone/refaster/matchers/IsEmpty.java +++ b/refaster-support/src/main/java/tech/picnic/errorprone/refaster/matchers/IsEmpty.java @@ -74,30 +74,30 @@ public final class IsEmpty implements Matcher { isSameType(Vector.class)); private static final Matcher EMPTY_INSTANCE_FACTORY = anyOf( - staticField(Collections.class.getName(), "EMPTY_LIST"), - staticField(Collections.class.getName(), "EMPTY_MAP"), - staticField(Collections.class.getName(), "EMPTY_SET"), + staticField(Collections.class.getCanonicalName(), "EMPTY_LIST"), + staticField(Collections.class.getCanonicalName(), "EMPTY_MAP"), + staticField(Collections.class.getCanonicalName(), "EMPTY_SET"), toType( MethodInvocationTree.class, allOf( argumentCount(0), anyOf( staticMethod() - .onClass(Collections.class.getName()) + .onClass(Collections.class.getCanonicalName()) .withNameMatching(EMPTY_INSTANCE_FACTORY_METHOD_PATTERN), staticMethod() .onDescendantOfAny( - ImmutableCollection.class.getName(), - ImmutableMap.class.getName(), - ImmutableMultimap.class.getName(), - List.class.getName(), - Map.class.getName(), - Set.class.getName(), - Stream.class.getName()) + ImmutableCollection.class.getCanonicalName(), + ImmutableMap.class.getCanonicalName(), + ImmutableMultimap.class.getCanonicalName(), + List.class.getCanonicalName(), + Map.class.getCanonicalName(), + Set.class.getCanonicalName(), + Stream.class.getCanonicalName()) .named("of"), staticMethod() .onClassAny( - Stream.class.getName(), + Stream.class.getCanonicalName(), "reactor.core.publisher.Flux", "reactor.core.publisher.Mono", "reactor.util.context.Context") diff --git a/refaster-support/src/main/java/tech/picnic/errorprone/refaster/matchers/IsIdentityOperation.java b/refaster-support/src/main/java/tech/picnic/errorprone/refaster/matchers/IsIdentityOperation.java index 706d61428f2..f69c4b40a67 100644 --- a/refaster-support/src/main/java/tech/picnic/errorprone/refaster/matchers/IsIdentityOperation.java +++ b/refaster-support/src/main/java/tech/picnic/errorprone/refaster/matchers/IsIdentityOperation.java @@ -25,10 +25,10 @@ public final class IsIdentityOperation implements Matcher { anyOf( staticMethod() .onDescendantOfAny( - DoubleUnaryOperator.class.getName(), - Function.class.getName(), - IntUnaryOperator.class.getName(), - LongUnaryOperator.class.getName()) + DoubleUnaryOperator.class.getCanonicalName(), + Function.class.getCanonicalName(), + IntUnaryOperator.class.getCanonicalName(), + LongUnaryOperator.class.getCanonicalName()) .named("identity"), isIdentityLambdaExpression()); diff --git a/refaster-support/src/main/java/tech/picnic/errorprone/refaster/matchers/IsRefasterAsVarargs.java b/refaster-support/src/main/java/tech/picnic/errorprone/refaster/matchers/IsRefasterAsVarargs.java index f9a4cd901d3..ffd2d43a027 100644 --- a/refaster-support/src/main/java/tech/picnic/errorprone/refaster/matchers/IsRefasterAsVarargs.java +++ b/refaster-support/src/main/java/tech/picnic/errorprone/refaster/matchers/IsRefasterAsVarargs.java @@ -11,7 +11,7 @@ public final class IsRefasterAsVarargs implements Matcher { private static final long serialVersionUID = 1L; private static final Matcher DELEGATE = - staticMethod().onClass(Refaster.class.getName()).named("asVarargs"); + staticMethod().onClass(Refaster.class.getCanonicalName()).named("asVarargs"); /** Instantiates a new {@link IsRefasterAsVarargs} instance. */ public IsRefasterAsVarargs() {}