diff --git a/check_api/src/main/java/com/google/errorprone/util/ASTHelpers.java b/check_api/src/main/java/com/google/errorprone/util/ASTHelpers.java index 2c52c2a3140..0e8cfc9e131 100644 --- a/check_api/src/main/java/com/google/errorprone/util/ASTHelpers.java +++ b/check_api/src/main/java/com/google/errorprone/util/ASTHelpers.java @@ -2274,6 +2274,10 @@ public static boolean containsComments(Tree tree, VisitorState state) { /** Returns whether {@code symbol} is final or effectively final. */ public static boolean isConsideredFinal(Symbol symbol) { + long flags = symbol.flags(); + boolean isEffectivelyFinal = (flags & Flags.EFFECTIVELY_FINAL) != 0; + System.out.println( + symbol + " (effectivelyFinal: " + isEffectivelyFinal + ", flags: " + flags + ")"); return (symbol.flags() & (Flags.FINAL | Flags.EFFECTIVELY_FINAL)) != 0; } diff --git a/core/src/test/java/com/google/errorprone/ErrorProneCompilerIntegrationTest.java b/core/src/test/java/com/google/errorprone/ErrorProneCompilerIntegrationTest.java index 824104ffbc6..8fbd4dde380 100644 --- a/core/src/test/java/com/google/errorprone/ErrorProneCompilerIntegrationTest.java +++ b/core/src/test/java/com/google/errorprone/ErrorProneCompilerIntegrationTest.java @@ -57,9 +57,11 @@ import java.util.Collections; import java.util.List; import java.util.Locale; +import java.util.stream.Collectors; import javax.inject.Inject; import javax.lang.model.element.Name; import javax.tools.Diagnostic; +import javax.tools.FileObject; import javax.tools.JavaFileObject; import org.junit.Before; import org.junit.Ignore; @@ -619,6 +621,89 @@ this.forbiddenString, constValue(tree.getExpression()).toString())) { } } + @Test + public void checkerBugGood() { + runTest("WARN", List.of(1, 2, 3)); + runTest("WARN", List.of(1, 3, 2)); + runTest("WARN", List.of(2, 1, 3)); + runTest("WARN", List.of(2, 3, 1)); + runTest("WARN", List.of(3, 1, 2)); + runTest("WARN", List.of(3, 2, 1)); + + // fails if 3 comes before 2 + + runTest("ERROR", List.of(1, 2, 3)); + // FAIL: runTest("ERROR", List.of(1, 3, 2)); + runTest("ERROR", List.of(2, 1, 3)); + runTest("ERROR", List.of(2, 3, 1)); + // FAIL: runTest("ERROR", List.of(3, 1, 2)); + // FAIL: runTest("ERROR", List.of(3, 2, 1)); + } + + @Test + public void checkerBugBad1() { + runTest("ERROR", List.of(1, 3, 2)); + } + + @Test + public void checkerBugBad2() { + runTest("ERROR", List.of(3, 1, 2)); + } + + @Test + public void checkerBugBad3() { + runTest("ERROR", List.of(3, 2, 1)); + } + + private void runTest(String unusedVariableSeverity, List fileOrder) { + JavaFileObject file1 = forSourceLines("GenericException.java", """ + package test; + import com.google.errorprone.annotations.FormatMethod; + public class GenericException extends Exception { + @FormatMethod + public GenericException(String message1, Object... args1) { + super(String.format(message1, args1)); + } + } + """); + JavaFileObject file2 = forSourceLines("SpecialException.java", """ + package test; + import com.google.errorprone.annotations.FormatMethod; + public class SpecialException extends GenericException { + @FormatMethod + public SpecialException(String message2, Object... args2) { + super(message2, args2); + } + } + """); + JavaFileObject file3 = forSourceLines("Violation.java", """ + package test; + public class Violation { + public void methodWithViolation() { + int x = 0; + } + } + """); + + List allFiles = Arrays.asList(file1, file2, file3); + List sources = fileOrder.stream().map(i -> allFiles.get(i - 1)).toList(); + + System.out.println("sources files: " + sources.stream() + .map(FileObject::getName) + .collect(Collectors.joining(", "))); + + String[] args = { + "-Xep:UnusedVariable:" + unusedVariableSeverity, + "-Xep:FormatStringAnnotation:ERROR" + }; + compiler = compilerBuilder.build(); + compiler.compile(args, sources); + outputStream.flush(); + String output = diagnosticHelper.getDiagnostics().toString(); + assertThat(output).contains(": [UnusedVariable]"); + assertThat(output).doesNotContain(": [FormatStringAnnotation]"); + } + @Test public void checkerWithFlags() { String[] args = {