Skip to content

Commit 85af056

Browse files
Stephan202Error Prone Team
authored and
Error Prone Team
committed
Propagate check flags in patch mode
Fixes #4699 COPYBARA_INTEGRATE_REVIEW=#4699 from PicnicSupermarket:sschroevers/unconditionally-apply-overrides 205c5a7 PiperOrigin-RevId: 711776790
1 parent 6a7ff67 commit 85af056

File tree

3 files changed

+171
-48
lines changed

3 files changed

+171
-48
lines changed

check_api/src/main/java/com/google/errorprone/ErrorProneAnalyzer.java

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import com.google.common.base.Suppliers;
2525
import com.google.common.collect.ImmutableSet;
2626
import com.google.errorprone.BugPattern.SeverityLevel;
27+
import com.google.errorprone.ErrorProneOptions.Severity;
2728
import com.google.errorprone.RefactoringCollection.RefactoringResult;
2829
import com.google.errorprone.scanner.ErrorProneScannerTransformer;
2930
import com.google.errorprone.scanner.ScannerSupplier;
@@ -79,15 +80,18 @@ public static ErrorProneAnalyzer createAnalyzer(
7980
.or(
8081
Suppliers.memoize(
8182
() -> {
82-
ScannerSupplier toUse =
83-
ErrorPronePlugins.loadPlugins(scannerSupplier, context);
8483
ImmutableSet<String> namedCheckers =
8584
epOptions.patchingOptions().namedCheckers();
86-
if (!namedCheckers.isEmpty()) {
87-
toUse = toUse.filter(bci -> namedCheckers.contains(bci.canonicalName()));
88-
} else {
89-
toUse = toUse.applyOverrides(epOptions);
90-
}
85+
ScannerSupplier toUse =
86+
ErrorPronePlugins.loadPlugins(scannerSupplier, context)
87+
.applyOverrides(epOptions)
88+
.filter(
89+
bci -> {
90+
String name = bci.canonicalName();
91+
return epOptions.getSeverityMap().get(name) != Severity.OFF
92+
&& (namedCheckers.isEmpty()
93+
|| namedCheckers.contains(name));
94+
});
9195
return ErrorProneScannerTransformer.create(toUse.get());
9296
}));
9397

core/src/test/java/com/google/errorprone/ErrorProneJavaCompilerTest.java

Lines changed: 160 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import com.google.errorprone.bugpatterns.BadShiftAmount;
3535
import com.google.errorprone.bugpatterns.BugChecker;
3636
import com.google.errorprone.bugpatterns.BugChecker.ClassTreeMatcher;
37+
import com.google.errorprone.bugpatterns.BugChecker.VariableTreeMatcher;
3738
import com.google.errorprone.bugpatterns.ChainingConstructorIgnoresParameter;
3839
import com.google.errorprone.bugpatterns.Finally;
3940
import com.google.errorprone.fixes.SuggestedFix;
@@ -42,21 +43,27 @@
4243
import com.google.errorprone.util.ASTHelpers;
4344
import com.sun.source.tree.ClassTree;
4445
import com.sun.source.tree.MethodTree;
46+
import com.sun.source.tree.VariableTree;
4547
import com.sun.tools.javac.file.JavacFileManager;
48+
import com.sun.tools.javac.util.Constants;
4649
import java.io.ByteArrayOutputStream;
4750
import java.io.IOException;
4851
import java.io.InputStream;
4952
import java.io.OutputStream;
5053
import java.io.OutputStreamWriter;
5154
import java.io.PrintWriter;
55+
import java.nio.file.Files;
56+
import java.nio.file.Path;
5257
import java.util.Arrays;
5358
import java.util.Collections;
5459
import java.util.List;
5560
import java.util.Locale;
61+
import javax.inject.Inject;
5662
import javax.lang.model.SourceVersion;
5763
import javax.tools.DiagnosticListener;
5864
import javax.tools.JavaCompiler;
5965
import javax.tools.JavaFileObject;
66+
import javax.tools.SimpleJavaFileObject;
6067
import org.junit.Rule;
6168
import org.junit.Test;
6269
import org.junit.rules.TemporaryFolder;
@@ -410,6 +417,150 @@ public void withExcludedPaths() {
410417
assertThat(result.succeeded).isFalse();
411418
}
412419

420+
@BugPattern(summary = "Test bug pattern to test custom patch functionality", severity = ERROR)
421+
public static final class AssignmentUpdater extends BugChecker implements VariableTreeMatcher {
422+
private final String newValue;
423+
424+
@Inject
425+
AssignmentUpdater(ErrorProneFlags flags) {
426+
newValue = flags.get("AssignmentUpdater:NewValue").orElse("flag-not-set");
427+
}
428+
429+
@Override
430+
public Description matchVariable(VariableTree tree, VisitorState state) {
431+
return describeMatch(
432+
tree, SuggestedFix.replace(tree.getInitializer(), Constants.format(newValue)));
433+
}
434+
}
435+
436+
@Test
437+
public void patchAll() throws IOException {
438+
JavaFileObject fileObject =
439+
createOnDiskFileObject(
440+
"StringConstantWrapper.java",
441+
"""
442+
class StringConstantWrapper {
443+
String s = "old-value";
444+
}
445+
""");
446+
447+
CompilationResult result =
448+
doCompile(
449+
Collections.singleton(fileObject),
450+
Arrays.asList("-XepPatchChecks:", "-XepPatchLocation:IN_PLACE"),
451+
ImmutableList.of(AssignmentUpdater.class));
452+
assertThat(result.succeeded).isTrue();
453+
assertThat(Files.readString(Path.of(fileObject.toUri())))
454+
.isEqualTo(
455+
"""
456+
class StringConstantWrapper {
457+
String s = "flag-not-set";
458+
}
459+
""");
460+
}
461+
462+
@Test
463+
public void patchAllWithCheckDisabled() throws IOException {
464+
JavaFileObject fileObject =
465+
createOnDiskFileObject(
466+
"StringConstantWrapper.java",
467+
"""
468+
class StringConstantWrapper {
469+
String s = "old-value";
470+
}
471+
""");
472+
473+
CompilationResult result =
474+
doCompile(
475+
Collections.singleton(fileObject),
476+
Arrays.asList(
477+
"-XepPatchChecks:", "-XepPatchLocation:IN_PLACE", "-Xep:AssignmentUpdater:OFF"),
478+
ImmutableList.of(AssignmentUpdater.class));
479+
assertThat(result.succeeded).isTrue();
480+
assertThat(Files.readString(Path.of(fileObject.toUri())))
481+
.isEqualTo(
482+
"""
483+
class StringConstantWrapper {
484+
String s = "old-value";
485+
}
486+
""");
487+
}
488+
489+
@Test
490+
public void patchSingleWithCheckDisabled() throws IOException {
491+
JavaFileObject fileObject =
492+
createOnDiskFileObject(
493+
"StringConstantWrapper.java",
494+
"""
495+
class StringConstantWrapper {
496+
String s = "old-value";
497+
}
498+
""");
499+
500+
CompilationResult result =
501+
doCompile(
502+
Collections.singleton(fileObject),
503+
Arrays.asList(
504+
"-XepPatchChecks:AssignmentUpdater",
505+
"-XepPatchLocation:IN_PLACE",
506+
"-Xep:AssignmentUpdater:OFF"),
507+
ImmutableList.of(AssignmentUpdater.class));
508+
assertThat(result.succeeded).isTrue();
509+
assertThat(Files.readString(Path.of(fileObject.toUri())))
510+
.isEqualTo(
511+
"""
512+
class StringConstantWrapper {
513+
String s = "old-value";
514+
}
515+
""");
516+
}
517+
518+
@Test
519+
public void patchSingleWithBugPatternCustomization() throws IOException {
520+
JavaFileObject fileObject =
521+
createOnDiskFileObject(
522+
"StringConstantWrapper.java",
523+
"""
524+
class StringConstantWrapper {
525+
String s = "old-value";
526+
}
527+
""");
528+
529+
CompilationResult result =
530+
doCompile(
531+
Collections.singleton(fileObject),
532+
Arrays.asList(
533+
"-XepPatchChecks:AssignmentUpdater",
534+
"-XepPatchLocation:IN_PLACE",
535+
"-XepOpt:AssignmentUpdater:NewValue=new-value"),
536+
ImmutableList.of(AssignmentUpdater.class));
537+
assertThat(result.succeeded).isTrue();
538+
assertThat(Files.readString(Path.of(fileObject.toUri())))
539+
.isEqualTo(
540+
"""
541+
class StringConstantWrapper {
542+
String s = "new-value";
543+
}
544+
""");
545+
}
546+
547+
/**
548+
* Creates a {@link JavaFileObject} with matching on-disk contents.
549+
*
550+
* <p>This method aids in testing patching functionality, as {@code IN_PLACE} patching requires
551+
* that compiled code actually exists on disk.
552+
*/
553+
private JavaFileObject createOnDiskFileObject(String fileName, String source) throws IOException {
554+
Path location = tempDir.getRoot().toPath().resolve(fileName);
555+
Files.writeString(location, source);
556+
return new SimpleJavaFileObject(location.toUri(), SimpleJavaFileObject.Kind.SOURCE) {
557+
@Override
558+
public String getCharContent(boolean ignoreEncodingErrors) {
559+
return source;
560+
}
561+
};
562+
}
563+
413564
private static class CompilationResult {
414565
public final boolean succeeded;
415566
public final String output;
@@ -427,6 +578,14 @@ private CompilationResult doCompile(
427578
List<String> fileNames,
428579
List<String> extraArgs,
429580
List<Class<? extends BugChecker>> customCheckers) {
581+
return doCompile(
582+
forResources(getClass(), fileNames.toArray(new String[0])), extraArgs, customCheckers);
583+
}
584+
585+
private CompilationResult doCompile(
586+
Iterable<? extends JavaFileObject> files,
587+
List<String> extraArgs,
588+
List<Class<? extends BugChecker>> customCheckers) {
430589
DiagnosticTestHelper diagnosticHelper = new DiagnosticTestHelper();
431590
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
432591
PrintWriter printWriter = new PrintWriter(new OutputStreamWriter(outputStream, UTF_8), true);
@@ -441,12 +600,7 @@ private CompilationResult doCompile(
441600
: new ErrorProneJavaCompiler(ScannerSupplier.fromBugCheckerClasses(customCheckers));
442601
JavaCompiler.CompilationTask task =
443602
errorProneJavaCompiler.getTask(
444-
printWriter,
445-
fileManager,
446-
diagnosticHelper.collector,
447-
args,
448-
null,
449-
forResources(getClass(), fileNames.toArray(new String[0])));
603+
printWriter, fileManager, diagnosticHelper.collector, args, null, files);
450604

451605
return new CompilationResult(
452606
task.call(), new String(outputStream.toByteArray(), UTF_8), diagnosticHelper);

core/src/test/java/com/google/errorprone/scanner/ScannerTest.java

Lines changed: 0 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -106,41 +106,6 @@ class Test {
106106
.doTest();
107107
}
108108

109-
@Test
110-
public void dontRunPatchForDisabledChecks() {
111-
compilationHelper
112-
.addSourceLines(
113-
"Test.java",
114-
"""
115-
import com.google.errorprone.scanner.ScannerTest.Foo;
116-
117-
class Test {
118-
Foo foo;
119-
}
120-
""")
121-
.setArgs("-XepPatchLocation:IN_PLACE", "-XepPatchChecks:", "-Xep:ShouldNotUseFoo:OFF")
122-
.doTest();
123-
}
124-
125-
@Test
126-
public void dontRunPatchUnlessRequested() {
127-
compilationHelper
128-
.addSourceLines(
129-
"Test.java",
130-
"""
131-
import com.google.errorprone.scanner.ScannerTest.Foo;
132-
133-
class Test {
134-
Foo foo;
135-
}
136-
""")
137-
.setArgs(
138-
"-XepPatchLocation:IN_PLACE",
139-
"-Xep:ShouldNotUseFoo:WARN",
140-
"-XepPatchChecks:DeadException")
141-
.doTest();
142-
}
143-
144109
@OkToUseFoo // Foo can use itself. But this shouldn't suppress errors on *usages* of Foo.
145110
public static final class Foo<T> {}
146111

0 commit comments

Comments
 (0)