Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,6 @@ class SuppressibleErrorPronePluginIntegrationTest extends ConfigurationCacheSpec
errorprone 'com.palantir.suppressible-error-prone:test-error-prone-checks:' + project.findProperty("suppressibleErrorProneVersion")
}


suppressibleErrorProne {
configureEachErrorProneOptions {
// These interfere with some tests, so disable them
Expand Down Expand Up @@ -1611,6 +1610,355 @@ class SuppressibleErrorPronePluginIntegrationTest extends ConfigurationCacheSpec
!output.contains('[RemoveRolloutSuppressions]')
}

def 'errorProneRemoveUnused removes only unused error-prone suppressions, and leaves unknown suppressions untouched'() {
// language=Java
writeJavaSourceFileToSourceSets '''
package app;

@SuppressWarnings({"ArrayToString", "UnnecessaryFinal", "InlineTrivialConstant", "NotAnErrorProne", "checkstyle:Bla",})
public final class App {
private static final String EMPTY_STRING = "";

public static void main(String[] args) {
new int[3].toString();
}
}
'''.stripIndent(true)

when:
runTasksSuccessfully('compileAllErrorProne', '-PerrorProneRemoveUnused=ArrayToString')

then:
// language=Java
javaSourceIsSyntacticallyEqualTo '''
package app;

@SuppressWarnings({"ArrayToString", "InlineTrivialConstant", "NotAnErrorProne", "checkstyle:Bla"})
public final class App {
private static final String EMPTY_STRING = "";

public static void main(String[] args) {
new int[3].toString();
}
}
'''.stripIndent(true)
}

def 'errorProneRemoveUnused only keeps the closest suppression to a violation'() {
// language=Java
writeJavaSourceFileToSourceSets '''
package app;

@SuppressWarnings("InlineTrivialConstant")
public final class App {
@SuppressWarnings("InlineTrivialConstant")
private static final String EMPTY_STRING = "";

@SuppressWarnings("InlineTrivialConstant")
class Inner {
@SuppressWarnings("InlineTrivialConstant")
class InnerInner {
@SuppressWarnings("InlineTrivialConstant")
class InnerInnerInner {
private static final String EMPTY = "";
}
}
}
}
'''.stripIndent(true)

when:
runTasksSuccessfully('compileAllErrorProne', '-PerrorProneRemoveUnused')

then:

// language=Java
javaSourceIsSyntacticallyEqualTo '''
package app;

public final class App {
@SuppressWarnings("InlineTrivialConstant")
private static final String EMPTY_STRING = "";

class Inner {
class InnerInner {
@SuppressWarnings("InlineTrivialConstant")
class InnerInnerInner {
private static final String EMPTY = "";
}
}
}
}
'''.stripIndent(true)
}

def 'errorProneRemoveUnused handles multiple suppressions on different tree types gracefully'() {
// Here we test the three types of trees you can suppress — ClassTree, MethodTree, VariableTree

// language=Java
writeJavaSourceFileToSourceSets '''
package app;

@SuppressWarnings({"ArrayEquals", "InlineTrivialConstant"})
public final class App {
@SuppressWarnings("InlineTrivialConstant")
private static final String EMPTY_STRING = "";

// Doesn't move an already existing suppression, even if it could be closer to the violation
@SuppressWarnings({"ArrayEquals", "InlineTrivialConstant"})
static class Inner {
@SuppressWarnings("InlineTrivialConstant")
private static final String EMPTY = "";
boolean truism = new int[3].equals(new int[3]);

@SuppressWarnings("InlineTrivialConstant")
static class InnerInner {
@SuppressWarnings({"ArrayEquals", "InlineTrivialConstant"})
void method() {
new int[3].equals(new int[3]);
}
}
}
}
'''.stripIndent(true)

when:
runTasksSuccessfully('compileAllErrorProne', '-PerrorProneRemoveUnused')

then:

// language=Java
javaSourceIsSyntacticallyEqualTo '''
package app;

public final class App {
@SuppressWarnings("InlineTrivialConstant")
private static final String EMPTY_STRING = "";

// Doesn't move an already existing suppression, even if it could be closer to the violation
@SuppressWarnings("ArrayEquals")
static class Inner {
@SuppressWarnings("InlineTrivialConstant")
private static final String EMPTY = "";

boolean truism = new int[3].equals(new int[3]);

static class InnerInner {
@SuppressWarnings("ArrayEquals")
void method() {
new int[3].equals(new int[3]);
}
}
}
}
'''.stripIndent(true)
}

def 'errorProneRemoveUnused removes entire SuppressWarnings annotation when all suppressions are unused'() {
// language=Java
writeJavaSourceFileToSourceSets '''
package app;

@SuppressWarnings({"UnusedVariable", "ArrayToString"})
public final class App {
public static void main(String[] args) {
System.out.println("No violations here");
}
}
'''.stripIndent(true)

when:
runTasksSuccessfully('compileAllErrorProne', '-PerrorProneRemoveUnused')

then:
// language=Java
javaSourceIsSyntacticallyEqualTo '''
package app;

public final class App {
public static void main(String[] args) {
System.out.println("No violations here");
}
}
'''.stripIndent(true)
}

def 'errorProneRemoveUnused and errorProneSuppress uses existing suppressions if possible'() {
// language=Java
writeJavaSourceFileToSourceSets '''
package app;

@SuppressWarnings("InlineTrivialConstant")
public final class App {
@SuppressWarnings("InlineTrivialConstant")
private static final String EMPTY_STRING = "";

@SuppressWarnings("InlineTrivialConstant")
static class Inner {
@SuppressWarnings("InlineTrivialConstant")
private static final String EMPTY = "";
boolean truism = new int[3].equals(new int[3]);

@SuppressWarnings("InlineTrivialConstant")
static class InnerInner {
@SuppressWarnings({"ArrayEquals", "InlineTrivialConstant"})
void method() {
new int[3].equals(new int[3]);
}
}
}
}
'''.stripIndent(true)

when:
runTasksSuccessfully('compileAllErrorProne', '-PerrorProneRemoveUnused', '-PerrorProneSuppress')

then:

// language=Java
javaSourceIsSyntacticallyEqualTo '''
package app;

public final class App {
@SuppressWarnings("InlineTrivialConstant")
private static final String EMPTY_STRING = "";

static class Inner {
@SuppressWarnings("InlineTrivialConstant")
private static final String EMPTY = "";

@SuppressWarnings("for-rollout:ArrayEquals")
boolean truism = new int[3].equals(new int[3]);

static class InnerInner {
@SuppressWarnings("ArrayEquals")
void method() {
new int[3].equals(new int[3]);
}
}
}
}
'''.stripIndent(true)
}

def 'errorProneRemoveUnused and errorProneApply applies fixes on previously suppressed elements'() {
// language=Java
writeJavaSourceFileToSourceSets '''
package app;
@SuppressWarnings({"ArrayEquals", "InlineTrivialConstant"})
public final class App {
@SuppressWarnings("InlineTrivialConstant")
private static final String EMPTY_STRING = "";

@SuppressWarnings({"ArrayEquals", "InlineTrivialConstant"})
static class Inner {
@SuppressWarnings("InlineTrivialConstant")
private static final String EMPTY = "";
boolean truism = new int[3].equals(new int[3]);

@SuppressWarnings("InlineTrivialConstant")
static class InnerInner {
@SuppressWarnings({"ArrayEquals", "InlineTrivialConstant"})
void method() {
new int[3].equals(new int[3]);
}
}
}
}
'''.stripIndent(true)

when:
runTasksSuccessfully('compileAllErrorProne', '-PerrorProneRemoveUnused', '-PerrorProneApply=ArrayEquals')

then:

// language=Java
javaSourceIsSyntacticallyEqualTo '''
package app;

import java.util.Arrays;

public final class App {
@SuppressWarnings("InlineTrivialConstant")
private static final String EMPTY_STRING = "";

static class Inner {
@SuppressWarnings("InlineTrivialConstant")
private static final String EMPTY = "";

boolean truism = Arrays.equals(new int[3], new int[3]);

static class InnerInner {
void method() {
Arrays.equals(new int[3], new int[3]);
}
}
}
}
'''.stripIndent(true)
}

def 'errorProneRemoveUnused + errorProneApply + errorProneSuppress applies fixes and suppressions on previously suppressed elements'() {
// language=Java
writeJavaSourceFileToSourceSets '''
package app;

@SuppressWarnings("ArrayEquals")
public final class App {
private static final String EMPTY_STRING = "";

// Although InlineTrivialConstant can be placed lower in the AST hierarchy,
// we preserve existing suppressions whenever possible rather than move suppressions around.
// Also, note that we don't add for-rollout here.
@SuppressWarnings({"ArrayEquals", "InlineTrivialConstant"})
static class Inner {
private static final String EMPTY = "";
boolean truism = new int[3].equals(new int[3]);

@SuppressWarnings("InlineTrivialConstant")
static class InnerInner {
@SuppressWarnings({"ArrayEquals", "InlineTrivialConstant"})
void method() {
new int[3].equals(new int[3]);
}
}
}
}
'''.stripIndent(true)

when:
runTasksSuccessfully('compileAllErrorProne', '-PerrorProneRemoveUnused', '-PerrorProneSuppress', '-PerrorProneApply=ArrayEquals')

then:

// language=Java
javaSourceIsSyntacticallyEqualTo '''
package app;

import java.util.Arrays;

public final class App {
@SuppressWarnings("for-rollout:InlineTrivialConstant")
private static final String EMPTY_STRING = "";

// Although InlineTrivialConstant can be placed lower in the AST hierarchy,
// we preserve existing suppressions whenever possible rather than move suppressions around.
// Also, note that we don't add for-rollout here.
@SuppressWarnings("InlineTrivialConstant")
static class Inner {
private static final String EMPTY = "";
boolean truism = Arrays.equals(new int[3], new int[3]);

static class InnerInner {
void method() {
Arrays.equals(new int[3], new int[3]);
}
}
}
}
'''.stripIndent(true)
}

def 'error-prone dependencies have versions bound together by a virtual platform'() {
setup: 'when an error-prone dependency is forced to certain version'
// language=Gradle
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,12 @@ final class ReportedFixCache {

public static final Predicate<String> REMOVE_EVERYTHING = bc -> false;
public static final Predicate<String> KEEP_EVERYTHING = bc -> true;
public static final Predicate<String> NOT_AN_ERRORPRONE = suppression -> {
String checkerName = suppression.startsWith(CommonConstants.AUTOMATICALLY_ADDED_PREFIX)
? suppression.substring(CommonConstants.AUTOMATICALLY_ADDED_PREFIX.length())
: suppression;
return !AllErrorprones.allBugcheckerNames().contains(checkerName);
};

ReportedFixCache() {}

Expand Down Expand Up @@ -67,6 +73,16 @@ public LazySuppressionFix reportNew(
return cache.put(declaration.getLeaf(), createAndReportFix(declaration, visitorState, filterExisting));
}

/**
* Gets an existing {@code LazySuppressionFix} on {@code declaration}
*/
public LazySuppressionFix getExisting(TreePath declaration) {
if (!cache.containsKey(declaration.getLeaf())) {
throw new IllegalArgumentException("A fix on this declaration must already exists");
}
return cache.get(declaration.getLeaf());
}

private LazySuppressionFix createAndReportFix(
TreePath declaration, VisitorState state, Predicate<String> filterExisting) {
if (!SuppressWarningsUtils.suppressibleTreePath(declaration)) {
Expand Down
Loading