Suggestions, introduce ErrorProneFork

This commit is contained in:
Stephan Schroevers
2022-09-29 23:24:05 +02:00
committed by Gijs de Jong
parent bb5fd10943
commit a9fa40804e
3 changed files with 64 additions and 40 deletions

View File

@@ -22,16 +22,13 @@ import com.sun.source.util.TreePath;
import com.sun.tools.javac.util.Context;
import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.Iterator;
import java.util.Optional;
import java.util.function.Function;
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
import tech.picnic.errorprone.refaster.annotation.Severity;
// XXX: Can we find a better name for this class? `CompositeAnnotatedCodeTransformer`, ...?
// XXX: Test this class directly. (Right now it's only indirectly tested through `RefasterTest`.)
@AutoValue
abstract class AnnotatedCompositeCodeTransformer implements CodeTransformer, Serializable {
@@ -127,25 +124,11 @@ abstract class AnnotatedCompositeCodeTransformer implements CodeTransformer, Ser
}
private static SeverityLevel overrideSeverity(SeverityLevel severity, Context context) {
ErrorProneOptions errorProneOptions = context.get(ErrorProneOptions.class);
SeverityLevel minSeverity = allSuggestionsAsWarnings(errorProneOptions) ? WARNING : SUGGESTION;
SeverityLevel maxSeverity = errorProneOptions.isDropErrorsToWarnings() ? WARNING : ERROR;
ErrorProneOptions options = context.get(ErrorProneOptions.class);
SeverityLevel minSeverity =
ErrorProneFork.isSuggestionsAsWarningsEnabled(options) ? WARNING : SUGGESTION;
SeverityLevel maxSeverity = options.isDropErrorsToWarnings() ? WARNING : ERROR;
return Comparators.max(Comparators.min(severity, minSeverity), maxSeverity);
}
private static boolean allSuggestionsAsWarnings(ErrorProneOptions errorProneOptions) {
try {
Optional<Method> isSuggestionsAsWarningsMethod =
Arrays.stream(errorProneOptions.getClass().getDeclaredMethods())
.filter(m -> Modifier.isPublic(m.getModifiers()))
.filter(m -> m.getName().equals("isSuggestionsAsWarnings"))
.findFirst();
return isSuggestionsAsWarningsMethod.isPresent()
&& Boolean.TRUE.equals(
isSuggestionsAsWarningsMethod.orElseThrow().invoke(errorProneOptions));
} catch (IllegalAccessException | InvocationTargetException e) {
return false;
}
}
}

View File

@@ -0,0 +1,58 @@
package tech.picnic.errorprone.refaster.plugin;
import com.google.errorprone.ErrorProneOptions;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.Optional;
/**
* Utility class that enables the runtime to determine whether Picnic's fork of Error Prone is on
* the classpath.
*
* @see <a href="https://github.com/PicnicSupermarket/error-prone">Picnic's Error Prone fork</a>
*/
// XXX: Add tests for this class. We can at least test `#isErrorProneForkAvailable()` by having
// Maven inject a corresponding system property.
public final class ErrorProneFork {
private static final Optional<Method> ERROR_PRONE_OPTIONS_IS_SUGGESTIONS_AS_WARNINGS_METHOD =
Arrays.stream(ErrorProneOptions.class.getDeclaredMethods())
.filter(m -> Modifier.isPublic(m.getModifiers()))
.filter(m -> "isSuggestionsAsWarnings".equals(m.getName()))
.findFirst();
private ErrorProneFork() {}
/**
* Tells whether Picnic's fork of Error Prone is available.
*
* @return {@code true} iff classpath introspection indicates the presence of Error Prone
* modifications that are assumed to be present only in Picnic's fork.
*/
public static boolean isErrorProneForkAvailable() {
return ERROR_PRONE_OPTIONS_IS_SUGGESTIONS_AS_WARNINGS_METHOD.isPresent();
}
/**
* Tells whether the custom {@code -XepAllSuggestionsAsWarnings} flag is set.
*
* @param options The currently active Error Prone options.
* @return {@code true} iff {@link #isErrorProneForkAvailable() the Error Prone fork is available}
* and the aforementioned flag is configured.
* @see <a href="https://github.com/google/error-prone/pull/3301">google/error-prone#3301</a>
*/
public static boolean isSuggestionsAsWarningsEnabled(ErrorProneOptions options) {
return ERROR_PRONE_OPTIONS_IS_SUGGESTIONS_AS_WARNINGS_METHOD
.filter(m -> Boolean.TRUE.equals(invoke(m, options)))
.isPresent();
}
private static Object invoke(Method method, Object obj, Object... args) {
try {
return method.invoke(obj, args);
} catch (IllegalAccessException | InvocationTargetException e) {
throw new IllegalStateException(String.format("Failed to invoke method '%s'", method), e);
}
}
}

View File

@@ -16,14 +16,13 @@ import com.google.errorprone.BugCheckerRefactoringTestHelper;
import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
import com.google.errorprone.BugPattern.SeverityLevel;
import com.google.errorprone.CompilationTestHelper;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.regex.Pattern;
import java.util.stream.Stream;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import tech.picnic.errorprone.refaster.plugin.ErrorProneFork;
final class RefasterTest {
private final CompilationTestHelper compilationHelper =
@@ -257,20 +256,4 @@ final class RefasterTest {
"}")
.doTest(TestMode.TEXT_MATCH);
}
private static boolean isBuiltWithErrorProneFork() {
Class<?> clazz;
try {
clazz =
Class.forName(
"com.google.errorprone.ErrorProneOptions",
/* initialize= */ false,
Thread.currentThread().getContextClassLoader());
} catch (ClassNotFoundException e) {
throw new IllegalStateException("Can't load `ErrorProneOptions` class", e);
}
return Arrays.stream(clazz.getDeclaredMethods())
.filter(m -> Modifier.isPublic(m.getModifiers()))
.anyMatch(m -> m.getName().equals("isSuggestionsAsWarnings"));
}
}