From 5413aa59a690e17135238961b232a846365f7d02 Mon Sep 17 00:00:00 2001 From: Liam Miller-Cushon Date: Tue, 30 Jul 2024 08:43:06 -0700 Subject: [PATCH] Recognize AutoValue extension generated code in ClassInitializationDeadlock and AutoValueSubclassLeaked PiperOrigin-RevId: 657606731 --- .../bugpatterns/AutoValueSubclassLeaked.java | 5 +++- .../ClassInitializationDeadlock.java | 6 +++- .../AutoValueSubclassLeakedTest.java | 29 +++++++++++++++++++ .../ClassInitializationDeadlockTest.java | 17 +++++++++++ 4 files changed, 55 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/com/google/errorprone/bugpatterns/AutoValueSubclassLeaked.java b/core/src/main/java/com/google/errorprone/bugpatterns/AutoValueSubclassLeaked.java index 60ecfe2b9f4..d43274e0cae 100644 --- a/core/src/main/java/com/google/errorprone/bugpatterns/AutoValueSubclassLeaked.java +++ b/core/src/main/java/com/google/errorprone/bugpatterns/AutoValueSubclassLeaked.java @@ -39,6 +39,7 @@ import com.sun.tools.javac.code.Symbol; import com.sun.tools.javac.code.Symbol.ClassSymbol; import com.sun.tools.javac.code.Type; +import java.util.regex.Pattern; /** Matches {@code AutoValue_} uses outside the containing file. */ @BugPattern( @@ -55,6 +56,8 @@ public final class AutoValueSubclassLeaked extends BugChecker implements CompilationUnitTreeMatcher { + private static final Pattern AUTO_VALUE_PREFIX = Pattern.compile("\\$*AutoValue_.*"); + @Override public Description matchCompilationUnit(CompilationUnitTree tree, VisitorState state) { ImmutableSet autoValueClassesFromThisFile = findAutoValueClasses(tree, state); @@ -91,7 +94,7 @@ public Void visitIdentifier(IdentifierTree identifierTree, Void unused) { private void handle(Tree tree) { Symbol symbol = getSymbol(tree); if (symbol instanceof ClassSymbol - && symbol.getSimpleName().toString().startsWith("AutoValue_") + && AUTO_VALUE_PREFIX.matcher(symbol.getSimpleName().toString()).matches() && autoValueClassesFromThisFile.stream() .noneMatch(av -> isSubtype(symbol.type, av, state))) { state.reportMatch(describeMatch(tree)); diff --git a/core/src/main/java/com/google/errorprone/bugpatterns/ClassInitializationDeadlock.java b/core/src/main/java/com/google/errorprone/bugpatterns/ClassInitializationDeadlock.java index ea569ddb2c3..7b9696c310d 100644 --- a/core/src/main/java/com/google/errorprone/bugpatterns/ClassInitializationDeadlock.java +++ b/core/src/main/java/com/google/errorprone/bugpatterns/ClassInitializationDeadlock.java @@ -48,11 +48,15 @@ import com.sun.tools.javac.code.Symbol.ClassSymbol; import com.sun.tools.javac.code.Type; import com.sun.tools.javac.code.Types; +import java.util.regex.Pattern; import javax.lang.model.element.ElementKind; /** See the summary. */ @BugPattern(summary = "Possible class initialization deadlock", severity = WARNING) public class ClassInitializationDeadlock extends BugChecker implements BugChecker.ClassTreeMatcher { + + private static final Pattern AUTO_VALUE_PREFIX = Pattern.compile("\\$*AutoValue_.*"); + @Override public Description matchClass(ClassTree tree, VisitorState state) { ClassSymbol classSymbol = getSymbol(tree); @@ -211,7 +215,7 @@ boolean nonPrivateInstantiator(ClassSymbol use) { // methods), it can't be directly instantiated outside the current file. return false; } - if (use.getSimpleName().toString().startsWith("AutoValue_")) { + if (AUTO_VALUE_PREFIX.matcher(use.getSimpleName().toString()).matches()) { // AutoValue generated code is necessarily package-private, but should only be accessed // within the declaration of the corresponding base class. See also the discussion of // AutoValue in diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/AutoValueSubclassLeakedTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/AutoValueSubclassLeakedTest.java index bf8061ff4b1..1c5ffe7fd06 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/AutoValueSubclassLeakedTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/AutoValueSubclassLeakedTest.java @@ -124,4 +124,33 @@ public void generatedCode() { "}") .doTest(); } + + @Test + public void positiveAutoValueExtension() { + helper + .addSourceLines( + "$$AutoValue_Foo.java", // + "package test;", + "class $$AutoValue_Foo extends Test.Foo {", + "}") + .addSourceLines( + "Test.java", + "package test;", + "import com.google.auto.value.AutoValue;", + "class Test {", + " @AutoValue", + " abstract static class Foo {", + " }", + "}") + .addSourceLines( + "Bar.java", + "package test;", + "class Bar {", + " public static Test.Foo create() {", + " // BUG: Diagnostic contains:", + " return new $$AutoValue_Foo();", + " }", + "}") + .doTest(); + } } diff --git a/core/src/test/java/com/google/errorprone/bugpatterns/ClassInitializationDeadlockTest.java b/core/src/test/java/com/google/errorprone/bugpatterns/ClassInitializationDeadlockTest.java index b1c51f7f1d1..ab3f981a75b 100644 --- a/core/src/test/java/com/google/errorprone/bugpatterns/ClassInitializationDeadlockTest.java +++ b/core/src/test/java/com/google/errorprone/bugpatterns/ClassInitializationDeadlockTest.java @@ -309,4 +309,21 @@ public void nonNestedSubclass() { "class B extends A {}") .doTest(); } + + @Test + public void negativeAutoValueExtension() { + testHelper + .addSourceLines( + "$$AutoValue_Foo.java", // + "class $$AutoValue_Foo extends Foo {", + "}") + .addSourceLines( + "A.java", + "import com.google.auto.value.AutoValue;", + "@AutoValue", + "abstract class Foo {", + " private static final Foo FOO = new $$AutoValue_Foo();", + "}") + .doTest(); + } }