mirror of
https://github.com/jlengrand/error-prone-support.git
synced 2026-03-10 15:49:33 +00:00
Compare commits
1 Commits
v0.15.0
...
sschroever
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cffff17c28 |
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>tech.picnic.error-prone-support</groupId>
|
||||
<artifactId>error-prone-support</artifactId>
|
||||
<version>0.15.0</version>
|
||||
<version>0.14.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>documentation-support</artifactId>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>tech.picnic.error-prone-support</groupId>
|
||||
<artifactId>error-prone-support</artifactId>
|
||||
<version>0.15.0</version>
|
||||
<version>0.14.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>error-prone-contrib</artifactId>
|
||||
|
||||
@@ -36,10 +36,6 @@ import tech.picnic.errorprone.utils.SourceCode;
|
||||
* <p>The idea behind this checker is that maintaining a sorted sequence simplifies conflict
|
||||
* resolution, and can even avoid it if two branches add the same annotation.
|
||||
*/
|
||||
// XXX: Currently this checker only flags method-level annotations. It should likely also flag
|
||||
// type-, field- and parameter-level annotations.
|
||||
// XXX: Duplicate entries are often a mistake. Consider introducing a similar `BugChecker` that
|
||||
// flags duplicates.
|
||||
@AutoService(BugChecker.class)
|
||||
@BugPattern(
|
||||
summary = "Sort annotations lexicographically where possible",
|
||||
|
||||
@@ -26,7 +26,6 @@ import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.function.Executable;
|
||||
import org.junit.jupiter.api.function.ThrowingSupplier;
|
||||
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
|
||||
import tech.picnic.errorprone.refaster.annotation.TypeMigration;
|
||||
|
||||
/**
|
||||
* Refaster rules to replace JUnit assertions with AssertJ equivalents.
|
||||
@@ -41,264 +40,6 @@ import tech.picnic.errorprone.refaster.annotation.TypeMigration;
|
||||
// `() -> toString()` match both `ThrowingSupplier` and `ThrowingCallable`, but `() -> "constant"`
|
||||
// is only compatible with the former.
|
||||
@OnlineDocumentation
|
||||
@TypeMigration(
|
||||
of = Assertions.class,
|
||||
unmigratedMethods = {
|
||||
"assertAll(Collection<Executable>)",
|
||||
"assertAll(Executable[])",
|
||||
"assertAll(Stream<Executable>)",
|
||||
"assertAll(String, Collection<Executable>)",
|
||||
"assertAll(String, Executable[])",
|
||||
"assertAll(String, Stream<Executable>)",
|
||||
"assertArrayEquals(boolean[], boolean[])",
|
||||
"assertArrayEquals(boolean[], boolean[], String)",
|
||||
"assertArrayEquals(boolean[], boolean[], Supplier<String>)",
|
||||
"assertArrayEquals(byte[], byte[])",
|
||||
"assertArrayEquals(byte[], byte[], String)",
|
||||
"assertArrayEquals(byte[], byte[], Supplier<String>)",
|
||||
"assertArrayEquals(char[], char[])",
|
||||
"assertArrayEquals(char[], char[], String)",
|
||||
"assertArrayEquals(char[], char[], Supplier<String>)",
|
||||
"assertArrayEquals(double[], double[])",
|
||||
"assertArrayEquals(double[], double[], double)",
|
||||
"assertArrayEquals(double[], double[], double, String)",
|
||||
"assertArrayEquals(double[], double[], double, Supplier<String>)",
|
||||
"assertArrayEquals(double[], double[], String)",
|
||||
"assertArrayEquals(double[], double[], Supplier<String>)",
|
||||
"assertArrayEquals(float[], float[])",
|
||||
"assertArrayEquals(float[], float[], float)",
|
||||
"assertArrayEquals(float[], float[], float, String)",
|
||||
"assertArrayEquals(float[], float[], float, Supplier<String>)",
|
||||
"assertArrayEquals(float[], float[], String)",
|
||||
"assertArrayEquals(float[], float[], Supplier<String>)",
|
||||
"assertArrayEquals(int[], int[])",
|
||||
"assertArrayEquals(int[], int[], String)",
|
||||
"assertArrayEquals(int[], int[], Supplier<String>)",
|
||||
"assertArrayEquals(long[], long[])",
|
||||
"assertArrayEquals(long[], long[], String)",
|
||||
"assertArrayEquals(long[], long[], Supplier<String>)",
|
||||
"assertArrayEquals(Object[], Object[])",
|
||||
"assertArrayEquals(Object[], Object[], String)",
|
||||
"assertArrayEquals(Object[], Object[], Supplier<String>)",
|
||||
"assertArrayEquals(short[], short[])",
|
||||
"assertArrayEquals(short[], short[], String)",
|
||||
"assertArrayEquals(short[], short[], Supplier<String>)",
|
||||
"assertEquals(Byte, Byte)",
|
||||
"assertEquals(Byte, byte)",
|
||||
"assertEquals(byte, Byte)",
|
||||
"assertEquals(byte, byte)",
|
||||
"assertEquals(Byte, Byte, String)",
|
||||
"assertEquals(Byte, byte, String)",
|
||||
"assertEquals(byte, Byte, String)",
|
||||
"assertEquals(byte, byte, String)",
|
||||
"assertEquals(Byte, Byte, Supplier<String>)",
|
||||
"assertEquals(Byte, byte, Supplier<String>)",
|
||||
"assertEquals(byte, Byte, Supplier<String>)",
|
||||
"assertEquals(byte, byte, Supplier<String>)",
|
||||
"assertEquals(char, char)",
|
||||
"assertEquals(char, char, String)",
|
||||
"assertEquals(char, char, Supplier<String>)",
|
||||
"assertEquals(char, Character)",
|
||||
"assertEquals(char, Character, String)",
|
||||
"assertEquals(char, Character, Supplier<String>)",
|
||||
"assertEquals(Character, char)",
|
||||
"assertEquals(Character, char, String)",
|
||||
"assertEquals(Character, char, Supplier<String>)",
|
||||
"assertEquals(Character, Character)",
|
||||
"assertEquals(Character, Character, String)",
|
||||
"assertEquals(Character, Character, Supplier<String>)",
|
||||
"assertEquals(Double, Double)",
|
||||
"assertEquals(Double, double)",
|
||||
"assertEquals(double, Double)",
|
||||
"assertEquals(double, double)",
|
||||
"assertEquals(double, double, double)",
|
||||
"assertEquals(double, double, double, String)",
|
||||
"assertEquals(double, double, double, Supplier<String>)",
|
||||
"assertEquals(Double, Double, String)",
|
||||
"assertEquals(Double, double, String)",
|
||||
"assertEquals(double, Double, String)",
|
||||
"assertEquals(double, double, String)",
|
||||
"assertEquals(Double, Double, Supplier<String>)",
|
||||
"assertEquals(Double, double, Supplier<String>)",
|
||||
"assertEquals(double, Double, Supplier<String>)",
|
||||
"assertEquals(double, double, Supplier<String>)",
|
||||
"assertEquals(Float, Float)",
|
||||
"assertEquals(Float, float)",
|
||||
"assertEquals(float, Float)",
|
||||
"assertEquals(float, float)",
|
||||
"assertEquals(float, float, float)",
|
||||
"assertEquals(float, float, float, String)",
|
||||
"assertEquals(float, float, float, Supplier<String>)",
|
||||
"assertEquals(Float, Float, String)",
|
||||
"assertEquals(Float, float, String)",
|
||||
"assertEquals(float, Float, String)",
|
||||
"assertEquals(float, float, String)",
|
||||
"assertEquals(Float, Float, Supplier<String>)",
|
||||
"assertEquals(Float, float, Supplier<String>)",
|
||||
"assertEquals(float, Float, Supplier<String>)",
|
||||
"assertEquals(float, float, Supplier<String>)",
|
||||
"assertEquals(int, int)",
|
||||
"assertEquals(int, int, String)",
|
||||
"assertEquals(int, int, Supplier<String>)",
|
||||
"assertEquals(int, Integer)",
|
||||
"assertEquals(int, Integer, String)",
|
||||
"assertEquals(int, Integer, Supplier<String>)",
|
||||
"assertEquals(Integer, int)",
|
||||
"assertEquals(Integer, int, String)",
|
||||
"assertEquals(Integer, int, Supplier<String>)",
|
||||
"assertEquals(Integer, Integer)",
|
||||
"assertEquals(Integer, Integer, String)",
|
||||
"assertEquals(Integer, Integer, Supplier<String>)",
|
||||
"assertEquals(Long, Long)",
|
||||
"assertEquals(Long, long)",
|
||||
"assertEquals(long, Long)",
|
||||
"assertEquals(long, long)",
|
||||
"assertEquals(Long, Long, String)",
|
||||
"assertEquals(Long, long, String)",
|
||||
"assertEquals(long, Long, String)",
|
||||
"assertEquals(long, long, String)",
|
||||
"assertEquals(Long, Long, Supplier<String>)",
|
||||
"assertEquals(Long, long, Supplier<String>)",
|
||||
"assertEquals(long, Long, Supplier<String>)",
|
||||
"assertEquals(long, long, Supplier<String>)",
|
||||
"assertEquals(Object, Object)",
|
||||
"assertEquals(Object, Object, String)",
|
||||
"assertEquals(Object, Object, Supplier<String>)",
|
||||
"assertEquals(Short, Short)",
|
||||
"assertEquals(Short, short)",
|
||||
"assertEquals(short, Short)",
|
||||
"assertEquals(short, short)",
|
||||
"assertEquals(Short, Short, String)",
|
||||
"assertEquals(Short, short, String)",
|
||||
"assertEquals(short, Short, String)",
|
||||
"assertEquals(short, short, String)",
|
||||
"assertEquals(Short, Short, Supplier<String>)",
|
||||
"assertEquals(Short, short, Supplier<String>)",
|
||||
"assertEquals(short, Short, Supplier<String>)",
|
||||
"assertEquals(short, short, Supplier<String>)",
|
||||
"assertFalse(BooleanSupplier)",
|
||||
"assertFalse(BooleanSupplier, String)",
|
||||
"assertFalse(BooleanSupplier, Supplier<String>)",
|
||||
"assertIterableEquals(Iterable<?>, Iterable<?>)",
|
||||
"assertIterableEquals(Iterable<?>, Iterable<?>, String)",
|
||||
"assertIterableEquals(Iterable<?>, Iterable<?>, Supplier<String>)",
|
||||
"assertLinesMatch(List<String>, List<String>)",
|
||||
"assertLinesMatch(List<String>, List<String>, String)",
|
||||
"assertLinesMatch(List<String>, List<String>, Supplier<String>)",
|
||||
"assertLinesMatch(Stream<String>, Stream<String>)",
|
||||
"assertLinesMatch(Stream<String>, Stream<String>, String)",
|
||||
"assertLinesMatch(Stream<String>, Stream<String>, Supplier<String>)",
|
||||
"assertNotEquals(Byte, Byte)",
|
||||
"assertNotEquals(Byte, byte)",
|
||||
"assertNotEquals(byte, Byte)",
|
||||
"assertNotEquals(byte, byte)",
|
||||
"assertNotEquals(Byte, Byte, String)",
|
||||
"assertNotEquals(Byte, byte, String)",
|
||||
"assertNotEquals(byte, Byte, String)",
|
||||
"assertNotEquals(byte, byte, String)",
|
||||
"assertNotEquals(Byte, Byte, Supplier<String>)",
|
||||
"assertNotEquals(Byte, byte, Supplier<String>)",
|
||||
"assertNotEquals(byte, Byte, Supplier<String>)",
|
||||
"assertNotEquals(byte, byte, Supplier<String>)",
|
||||
"assertNotEquals(char, char)",
|
||||
"assertNotEquals(char, char, String)",
|
||||
"assertNotEquals(char, char, Supplier<String>)",
|
||||
"assertNotEquals(char, Character)",
|
||||
"assertNotEquals(char, Character, String)",
|
||||
"assertNotEquals(char, Character, Supplier<String>)",
|
||||
"assertNotEquals(Character, char)",
|
||||
"assertNotEquals(Character, char, String)",
|
||||
"assertNotEquals(Character, char, Supplier<String>)",
|
||||
"assertNotEquals(Character, Character)",
|
||||
"assertNotEquals(Character, Character, String)",
|
||||
"assertNotEquals(Character, Character, Supplier<String>)",
|
||||
"assertNotEquals(Double, Double)",
|
||||
"assertNotEquals(Double, double)",
|
||||
"assertNotEquals(double, Double)",
|
||||
"assertNotEquals(double, double)",
|
||||
"assertNotEquals(double, double, double)",
|
||||
"assertNotEquals(double, double, double, String)",
|
||||
"assertNotEquals(double, double, double, Supplier<String>)",
|
||||
"assertNotEquals(Double, Double, String)",
|
||||
"assertNotEquals(Double, double, String)",
|
||||
"assertNotEquals(double, Double, String)",
|
||||
"assertNotEquals(double, double, String)",
|
||||
"assertNotEquals(Double, Double, Supplier<String>)",
|
||||
"assertNotEquals(Double, double, Supplier<String>)",
|
||||
"assertNotEquals(double, Double, Supplier<String>)",
|
||||
"assertNotEquals(double, double, Supplier<String>)",
|
||||
"assertNotEquals(Float, Float)",
|
||||
"assertNotEquals(Float, float)",
|
||||
"assertNotEquals(float, Float)",
|
||||
"assertNotEquals(float, float)",
|
||||
"assertNotEquals(float, float, float)",
|
||||
"assertNotEquals(float, float, float, String)",
|
||||
"assertNotEquals(float, float, float, Supplier<String>)",
|
||||
"assertNotEquals(Float, Float, String)",
|
||||
"assertNotEquals(Float, float, String)",
|
||||
"assertNotEquals(float, Float, String)",
|
||||
"assertNotEquals(float, float, String)",
|
||||
"assertNotEquals(Float, Float, Supplier<String>)",
|
||||
"assertNotEquals(Float, float, Supplier<String>)",
|
||||
"assertNotEquals(float, Float, Supplier<String>)",
|
||||
"assertNotEquals(float, float, Supplier<String>)",
|
||||
"assertNotEquals(int, int)",
|
||||
"assertNotEquals(int, int, String)",
|
||||
"assertNotEquals(int, int, Supplier<String>)",
|
||||
"assertNotEquals(int, Integer)",
|
||||
"assertNotEquals(int, Integer, String)",
|
||||
"assertNotEquals(int, Integer, Supplier<String>)",
|
||||
"assertNotEquals(Integer, int)",
|
||||
"assertNotEquals(Integer, int, String)",
|
||||
"assertNotEquals(Integer, int, Supplier<String>)",
|
||||
"assertNotEquals(Integer, Integer)",
|
||||
"assertNotEquals(Integer, Integer, String)",
|
||||
"assertNotEquals(Integer, Integer, Supplier<String>)",
|
||||
"assertNotEquals(Long, Long)",
|
||||
"assertNotEquals(Long, long)",
|
||||
"assertNotEquals(long, Long)",
|
||||
"assertNotEquals(long, long)",
|
||||
"assertNotEquals(Long, Long, String)",
|
||||
"assertNotEquals(Long, long, String)",
|
||||
"assertNotEquals(long, Long, String)",
|
||||
"assertNotEquals(long, long, String)",
|
||||
"assertNotEquals(Long, Long, Supplier<String>)",
|
||||
"assertNotEquals(Long, long, Supplier<String>)",
|
||||
"assertNotEquals(long, Long, Supplier<String>)",
|
||||
"assertNotEquals(long, long, Supplier<String>)",
|
||||
"assertNotEquals(Object, Object)",
|
||||
"assertNotEquals(Object, Object, String)",
|
||||
"assertNotEquals(Object, Object, Supplier<String>)",
|
||||
"assertNotEquals(Short, Short)",
|
||||
"assertNotEquals(Short, short)",
|
||||
"assertNotEquals(short, Short)",
|
||||
"assertNotEquals(short, short)",
|
||||
"assertNotEquals(Short, Short, String)",
|
||||
"assertNotEquals(Short, short, String)",
|
||||
"assertNotEquals(short, Short, String)",
|
||||
"assertNotEquals(short, short, String)",
|
||||
"assertNotEquals(Short, Short, Supplier<String>)",
|
||||
"assertNotEquals(Short, short, Supplier<String>)",
|
||||
"assertNotEquals(short, Short, Supplier<String>)",
|
||||
"assertNotEquals(short, short, Supplier<String>)",
|
||||
"assertTimeout(Duration, Executable)",
|
||||
"assertTimeout(Duration, Executable, String)",
|
||||
"assertTimeout(Duration, Executable, Supplier<String>)",
|
||||
"assertTimeout(Duration, ThrowingSupplier<T>)",
|
||||
"assertTimeout(Duration, ThrowingSupplier<T>, String)",
|
||||
"assertTimeout(Duration, ThrowingSupplier<T>, Supplier<String>)",
|
||||
"assertTimeoutPreemptively(Duration, Executable)",
|
||||
"assertTimeoutPreemptively(Duration, Executable, String)",
|
||||
"assertTimeoutPreemptively(Duration, Executable, Supplier<String>)",
|
||||
"assertTimeoutPreemptively(Duration, ThrowingSupplier<T>)",
|
||||
"assertTimeoutPreemptively(Duration, ThrowingSupplier<T>, String)",
|
||||
"assertTimeoutPreemptively(Duration, ThrowingSupplier<T>, Supplier<String>)",
|
||||
"assertTimeoutPreemptively(Duration, ThrowingSupplier<T>, Supplier<String>, TimeoutFailureFactory<E>)",
|
||||
"assertTrue(BooleanSupplier)",
|
||||
"assertTrue(BooleanSupplier, String)",
|
||||
"assertTrue(BooleanSupplier, Supplier<String>)",
|
||||
"fail(Supplier<String>)"
|
||||
})
|
||||
final class JUnitToAssertJRules {
|
||||
private JUnitToAssertJRules() {}
|
||||
|
||||
|
||||
@@ -728,6 +728,27 @@ final class ReactorRules {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer {@link Mono#map(Function)} over alternatives that unnecessarily create and collect a
|
||||
* {@link Flux}.
|
||||
*/
|
||||
// XXX: This rule assumes that any matched `Collector` does not filter or reorder elements after
|
||||
// application of the matched `Function`.
|
||||
// XXX: The `function` parameter is not matched, unless `I` is changed to `Iterable<? extends S>`,
|
||||
// which would make the rule incorrect.
|
||||
static final class MonoMapToIterable<T, S, I extends Iterable<? extends S>> {
|
||||
@BeforeTemplate
|
||||
Mono<I> before(
|
||||
Mono<T> mono, Function<? super T, ? extends I> function, Collector<S, ?, I> collector) {
|
||||
return mono.flatMapIterable(function).collect(collector);
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Mono<I> after(Mono<T> mono, Function<? super T, ? extends I> function) {
|
||||
return mono.map(function);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer {@link Flux#map(Function)} over alternatives that unnecessarily require an inner
|
||||
* subscription.
|
||||
@@ -1694,6 +1715,26 @@ final class ReactorRules {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer {@link Flux#singleOrEmpty()} over {@link Flux#next()} when the {@link Flux} emits at
|
||||
* most one element.
|
||||
*/
|
||||
// XXX: This is a special case of a more general rule. Consider introducing an Error Prone check
|
||||
// for this.
|
||||
// XXX: The `transformer` parameter isn't matched, unless the signature is changed to `? extends
|
||||
// Publisher<S>`, which would make the rule incorrect.
|
||||
static final class FluxTransformToMonoSingleOrEmpty<T, S> {
|
||||
@BeforeTemplate
|
||||
Mono<S> before(Flux<T> flux, Function<? super Flux<T>, ? extends Mono<S>> transformer) {
|
||||
return flux.transform(transformer).next();
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
Mono<S> after(Flux<T> flux, Function<? super Flux<T>, ? extends Mono<S>> transformer) {
|
||||
return flux.transform(transformer).singleOrEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer {@link reactor.util.context.Context#empty()}} over more verbose alternatives. */
|
||||
// XXX: Introduce Refaster rules or a `BugChecker` that maps `(Immutable)Map.of(k, v)` to
|
||||
// `Context.of(k, v)` and likewise for multi-pair overloads.
|
||||
|
||||
@@ -4,7 +4,6 @@ import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
|
||||
import static java.util.Comparator.naturalOrder;
|
||||
import static java.util.Comparator.reverseOrder;
|
||||
import static java.util.function.Predicate.not;
|
||||
import static java.util.stream.Collectors.collectingAndThen;
|
||||
import static java.util.stream.Collectors.counting;
|
||||
import static java.util.stream.Collectors.filtering;
|
||||
import static java.util.stream.Collectors.flatMapping;
|
||||
@@ -38,7 +37,6 @@ import java.util.Comparator;
|
||||
import java.util.DoubleSummaryStatistics;
|
||||
import java.util.IntSummaryStatistics;
|
||||
import java.util.LongSummaryStatistics;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.function.BinaryOperator;
|
||||
@@ -256,21 +254,15 @@ final class StreamRules {
|
||||
// XXX: This rule assumes that any matched `Collector` does not perform any filtering.
|
||||
// (Perhaps we could add a `@Matches` guard that validates that the collector expression does not
|
||||
// contain a `Collectors#filtering` call. That'd still not be 100% accurate, though.)
|
||||
static final class StreamIsEmpty<T, K, V, C extends Collection<K>, M extends Map<K, V>> {
|
||||
static final class StreamIsEmpty<T> {
|
||||
@BeforeTemplate
|
||||
boolean before(Stream<T> stream, Collector<? super T, ?, ? extends C> collector) {
|
||||
boolean before(Stream<T> stream, Collector<? super T, ?, ? extends Collection<?>> collector) {
|
||||
return Refaster.anyOf(
|
||||
stream.count() == 0,
|
||||
stream.count() <= 0,
|
||||
stream.count() < 1,
|
||||
stream.findFirst().isEmpty(),
|
||||
stream.collect(collector).isEmpty(),
|
||||
stream.collect(collectingAndThen(collector, C::isEmpty)));
|
||||
}
|
||||
|
||||
@BeforeTemplate
|
||||
boolean before2(Stream<T> stream, Collector<? super T, ?, ? extends M> collector) {
|
||||
return stream.collect(collectingAndThen(collector, M::isEmpty));
|
||||
stream.collect(collector).isEmpty());
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
|
||||
@@ -162,39 +162,6 @@ final class StringRules {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer direct invocation of {@link String#String(char[], int, int)} over the indirection
|
||||
* introduced by alternatives.
|
||||
*/
|
||||
static final class NewStringFromCharArraySubSequence {
|
||||
@BeforeTemplate
|
||||
String before(char[] data, int offset, int count) {
|
||||
return Refaster.anyOf(
|
||||
String.valueOf(data, offset, count), String.copyValueOf(data, offset, count));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
String after(char[] data, int offset, int count) {
|
||||
return new String(data, offset, count);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer direct invocation of {@link String#String(char[])} over the indirection introduced by
|
||||
* alternatives.
|
||||
*/
|
||||
static final class NewStringFromCharArray {
|
||||
@BeforeTemplate
|
||||
String before(char[] data) {
|
||||
return Refaster.anyOf(String.valueOf(data), new String(data, 0, data.length));
|
||||
}
|
||||
|
||||
@AfterTemplate
|
||||
String after(char[] data) {
|
||||
return new String(data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer direct delegation to {@link String#valueOf(Object)} over the indirection introduced by
|
||||
* {@link Objects#toString(Object)}.
|
||||
|
||||
@@ -29,7 +29,6 @@ import org.assertj.core.api.ThrowableAssert.ThrowingCallable;
|
||||
import org.testng.Assert;
|
||||
import org.testng.Assert.ThrowingRunnable;
|
||||
import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
|
||||
import tech.picnic.errorprone.refaster.annotation.TypeMigration;
|
||||
|
||||
/**
|
||||
* Refaster rules that replace TestNG assertions with equivalent AssertJ assertions.
|
||||
@@ -49,107 +48,32 @@ import tech.picnic.errorprone.refaster.annotation.TypeMigration;
|
||||
* List<Map<String, Object>> myMaps = new ArrayList<>();
|
||||
* assertEquals(myMaps, ImmutableList.of(ImmutableMap.of()));
|
||||
* }</pre>
|
||||
*
|
||||
* <p>A few {@link Assert} methods are not rewritten:
|
||||
*
|
||||
* <ul>
|
||||
* <li>These methods cannot (easily) be expressed using AssertJ because they mix regular equality
|
||||
* and array equality:
|
||||
* <ul>
|
||||
* <li>{@link Assert#assertEqualsDeep(Map, Map)}
|
||||
* <li>{@link Assert#assertEqualsDeep(Map, Map, String)}
|
||||
* <li>{@link Assert#assertEqualsDeep(Set, Set, String)}
|
||||
* <li>{@link Assert#assertNotEqualsDeep(Map, Map)}
|
||||
* <li>{@link Assert#assertNotEqualsDeep(Map, Map, String)}
|
||||
* <li>{@link Assert#assertNotEqualsDeep(Set, Set)}
|
||||
* <li>{@link Assert#assertNotEqualsDeep(Set, Set, String)}
|
||||
* </ul>
|
||||
* <li>This method returns the caught exception; there is no direct counterpart for this in
|
||||
* AssertJ:
|
||||
* <ul>
|
||||
* <li>{@link Assert#expectThrows(Class, ThrowingRunnable)}
|
||||
* </ul>
|
||||
* </ul>
|
||||
*/
|
||||
// XXX: As-is these rules do not result in a complete migration:
|
||||
// - Expressions containing comments are skipped due to a limitation of Refaster.
|
||||
// - Assertions inside lambda expressions are also skipped. Unclear why.
|
||||
// XXX: The `assertEquals` tests for this class generally use the same expression for `expected` and
|
||||
// `actual`, which makes the validation weaker than necessary; fix this. (And investigate whether we
|
||||
// can introduce validation for this.)
|
||||
@OnlineDocumentation
|
||||
@TypeMigration(
|
||||
of = Assert.class,
|
||||
unmigratedMethods = {
|
||||
// XXX: Add migrations for the methods below.
|
||||
"assertEquals(Boolean, Boolean)",
|
||||
"assertEquals(Boolean, boolean)",
|
||||
"assertEquals(boolean, Boolean)",
|
||||
"assertEquals(Boolean, Boolean, String)",
|
||||
"assertEquals(Boolean, boolean, String)",
|
||||
"assertEquals(boolean, Boolean, String)",
|
||||
"assertEquals(Byte, Byte)",
|
||||
"assertEquals(Byte, byte)",
|
||||
"assertEquals(byte, Byte)",
|
||||
"assertEquals(Byte, Byte, String)",
|
||||
"assertEquals(Byte, byte, String)",
|
||||
"assertEquals(byte, Byte, String)",
|
||||
"assertEquals(char, Character)",
|
||||
"assertEquals(char, Character, String)",
|
||||
"assertEquals(Character, char)",
|
||||
"assertEquals(Character, char, String)",
|
||||
"assertEquals(Character, Character)",
|
||||
"assertEquals(Character, Character, String)",
|
||||
"assertEquals(Double, Double)",
|
||||
"assertEquals(Double, double)",
|
||||
"assertEquals(double, Double)",
|
||||
"assertEquals(Double, Double, String)",
|
||||
"assertEquals(Double, double, String)",
|
||||
"assertEquals(double, Double, String)",
|
||||
"assertEquals(double[], double[], double)",
|
||||
"assertEquals(double[], double[], double, String)",
|
||||
"assertEquals(Float, Float)",
|
||||
"assertEquals(Float, float)",
|
||||
"assertEquals(float, Float)",
|
||||
"assertEquals(Float, Float, String)",
|
||||
"assertEquals(Float, float, String)",
|
||||
"assertEquals(float, Float, String)",
|
||||
"assertEquals(float[], float[], float)",
|
||||
"assertEquals(float[], float[], float, String)",
|
||||
"assertEquals(int, Integer)",
|
||||
"assertEquals(int, Integer, String)",
|
||||
"assertEquals(Integer, int)",
|
||||
"assertEquals(Integer, int, String)",
|
||||
"assertEquals(Integer, Integer)",
|
||||
"assertEquals(Integer, Integer, String)",
|
||||
"assertEquals(Long, Long)",
|
||||
"assertEquals(Long, long)",
|
||||
"assertEquals(long, Long)",
|
||||
"assertEquals(Long, Long, String)",
|
||||
"assertEquals(Long, long, String)",
|
||||
"assertEquals(Short, Short)",
|
||||
"assertEquals(Short, short)",
|
||||
"assertEquals(short, Short)",
|
||||
"assertEquals(Short, Short, String)",
|
||||
"assertEquals(Short, short, String)",
|
||||
"assertEquals(short, Short, String)",
|
||||
/*
|
||||
* These `assertEqualsDeep` methods cannot (easily) be expressed using AssertJ because they
|
||||
* mix regular equality and array equality:
|
||||
*/
|
||||
"assertEqualsDeep(Map<?, ?>, Map<?, ?>)",
|
||||
"assertEqualsDeep(Map<?, ?>, Map<?, ?>, String)",
|
||||
"assertEqualsDeep(Set<?>, Set<?>, String)",
|
||||
// XXX: Add migrations for the methods below.
|
||||
"assertEqualsNoOrder(Collection<?>, Collection<?>)",
|
||||
"assertEqualsNoOrder(Collection<?>, Collection<?>, String)",
|
||||
"assertEqualsNoOrder(Iterator<?>, Iterator<?>)",
|
||||
"assertEqualsNoOrder(Iterator<?>, Iterator<?>, String)",
|
||||
"assertListContains(List<T>, Predicate<T>, String)",
|
||||
"assertListContainsObject(List<T>, T, String)",
|
||||
"assertListNotContains(List<T>, Predicate<T>, String)",
|
||||
"assertListNotContainsObject(List<T>, T, String)",
|
||||
"assertNotEquals(Collection<?>, Collection<?>)",
|
||||
"assertNotEquals(Collection<?>, Collection<?>, String)",
|
||||
"assertNotEquals(Iterator<?>, Iterator<?>)",
|
||||
"assertNotEquals(Iterator<?>, Iterator<?>, String)",
|
||||
"assertNotEquals(Object[], Object[], String)",
|
||||
/*
|
||||
* These `assertNotEqualsDeep` methods cannot (easily) be expressed using AssertJ because they
|
||||
* mix regular equality and array equality:
|
||||
*/
|
||||
"assertNotEqualsDeep(Map<?, ?>, Map<?, ?>)",
|
||||
"assertNotEqualsDeep(Map<?, ?>, Map<?, ?>, String)",
|
||||
"assertNotEqualsDeep(Set<?>, Set<?>)",
|
||||
"assertNotEqualsDeep(Set<?>, Set<?>, String)",
|
||||
// XXX: Add a migration for this `assertThrows` method.
|
||||
"assertThrows(String, Class<T>, ThrowingRunnable)",
|
||||
/*
|
||||
* These `expectThrows` methods return the caught exception; there is no direct counterpart
|
||||
* for this in AssertJ.
|
||||
*/
|
||||
"expectThrows(Class<T>, ThrowingRunnable)",
|
||||
"expectThrows(String, Class<T>, ThrowingRunnable)"
|
||||
})
|
||||
final class TestNGToAssertJRules {
|
||||
private TestNGToAssertJRules() {}
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package tech.picnic.errorprone.refasterrules;
|
||||
|
||||
import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
import static com.google.common.collect.ImmutableSet.toImmutableSet;
|
||||
import static com.google.common.collect.ImmutableSortedSet.toImmutableSortedSet;
|
||||
import static com.google.common.collect.MoreCollectors.toOptional;
|
||||
import static java.util.Comparator.naturalOrder;
|
||||
import static java.util.Comparator.reverseOrder;
|
||||
@@ -14,8 +16,10 @@ import com.google.common.collect.ImmutableCollection;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.ImmutableSortedSet;
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@@ -262,6 +266,16 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
Mono.just("bar").flatMap(s -> Mono.just(s.substring(1))));
|
||||
}
|
||||
|
||||
ImmutableSet<Mono<Iterable<String>>> testMonoMapToIterable() {
|
||||
return ImmutableSet.of(
|
||||
Mono.just("foo").flatMapIterable(ImmutableSet::of).collect(toImmutableSet()),
|
||||
Mono.just("bar").flatMapIterable(ImmutableSortedSet::of).collect(toImmutableSet()),
|
||||
Mono.just("baz")
|
||||
.flatMapIterable(ImmutableSet::of)
|
||||
.collect(toImmutableSortedSet(naturalOrder())),
|
||||
Mono.just("qux").flatMapIterable(Arrays::asList).collect(toCollection(ArrayList::new)));
|
||||
}
|
||||
|
||||
ImmutableSet<Flux<Integer>> testFluxMap() {
|
||||
return ImmutableSet.of(
|
||||
Flux.just(1).concatMap(n -> Mono.just(n)),
|
||||
@@ -571,6 +585,10 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
MathFlux.min(Flux.just(1), reverseOrder()), MathFlux.max(Flux.just(2), naturalOrder()));
|
||||
}
|
||||
|
||||
Mono<String> testFluxTransformToMonoSingleOrEmpty() {
|
||||
return Flux.just("foo").transform(Flux::next).next();
|
||||
}
|
||||
|
||||
ImmutableSet<Context> testContextEmpty() {
|
||||
return ImmutableSet.of(Context.of(ImmutableMap.of()), Context.of(ImmutableMap.of(1, 2)));
|
||||
}
|
||||
|
||||
@@ -16,8 +16,10 @@ import com.google.common.collect.ImmutableCollection;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.ImmutableSortedSet;
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@@ -263,6 +265,14 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return ImmutableSet.of(Mono.just("foo").map(s -> s), Mono.just("bar").map(s -> s.substring(1)));
|
||||
}
|
||||
|
||||
ImmutableSet<Mono<Iterable<String>>> testMonoMapToIterable() {
|
||||
return ImmutableSet.of(
|
||||
Mono.just("foo").map(ImmutableSet::of),
|
||||
Mono.just("bar").map(ImmutableSortedSet::of),
|
||||
Mono.just("baz").map(ImmutableSet::of),
|
||||
Mono.just("qux").map(Arrays::asList));
|
||||
}
|
||||
|
||||
ImmutableSet<Flux<Integer>> testFluxMap() {
|
||||
return ImmutableSet.of(
|
||||
Flux.just(1).map(n -> n),
|
||||
@@ -560,6 +570,10 @@ final class ReactorRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return ImmutableSet.of(MathFlux.max(Flux.just(1)), MathFlux.max(Flux.just(2)));
|
||||
}
|
||||
|
||||
Mono<String> testFluxTransformToMonoSingleOrEmpty() {
|
||||
return Flux.just("foo").transform(Flux::next).singleOrEmpty();
|
||||
}
|
||||
|
||||
ImmutableSet<Context> testContextEmpty() {
|
||||
return ImmutableSet.of(Context.empty(), Context.of(ImmutableMap.of(1, 2)));
|
||||
}
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
package tech.picnic.errorprone.refasterrules;
|
||||
|
||||
import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
import static com.google.common.collect.ImmutableMap.toImmutableMap;
|
||||
import static com.google.common.collect.ImmutableSet.toImmutableSet;
|
||||
import static java.util.Comparator.comparingInt;
|
||||
import static java.util.Comparator.reverseOrder;
|
||||
import static java.util.function.Function.identity;
|
||||
import static java.util.function.Predicate.not;
|
||||
import static java.util.stream.Collectors.collectingAndThen;
|
||||
import static java.util.stream.Collectors.counting;
|
||||
import static java.util.stream.Collectors.filtering;
|
||||
import static java.util.stream.Collectors.flatMapping;
|
||||
@@ -24,14 +21,11 @@ import static java.util.stream.Collectors.summingInt;
|
||||
import static java.util.stream.Collectors.summingLong;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Streams;
|
||||
import java.util.DoubleSummaryStatistics;
|
||||
import java.util.IntSummaryStatistics;
|
||||
import java.util.List;
|
||||
import java.util.LongSummaryStatistics;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
@@ -44,12 +38,8 @@ final class StreamRulesTest implements RefasterRuleCollectionTestCase {
|
||||
public ImmutableSet<Object> elidedTypesAndStaticImports() {
|
||||
return ImmutableSet.of(
|
||||
ImmutableList.class,
|
||||
ImmutableMap.class,
|
||||
List.class,
|
||||
Map.class,
|
||||
Objects.class,
|
||||
Streams.class,
|
||||
collectingAndThen(null, null),
|
||||
counting(),
|
||||
filtering(null, null),
|
||||
flatMapping(null, null),
|
||||
@@ -64,9 +54,7 @@ final class StreamRulesTest implements RefasterRuleCollectionTestCase {
|
||||
summarizingLong(null),
|
||||
summingDouble(null),
|
||||
summingInt(null),
|
||||
summingLong(null),
|
||||
toImmutableList(),
|
||||
toImmutableMap(null, null));
|
||||
summingLong(null));
|
||||
}
|
||||
|
||||
String testJoining() {
|
||||
@@ -126,12 +114,7 @@ final class StreamRulesTest implements RefasterRuleCollectionTestCase {
|
||||
Stream.of(2).count() <= 0,
|
||||
Stream.of(3).count() < 1,
|
||||
Stream.of(4).findFirst().isEmpty(),
|
||||
Stream.of(5).collect(toImmutableSet()).isEmpty(),
|
||||
Stream.of(6).collect(collectingAndThen(toImmutableList(), List::isEmpty)),
|
||||
Stream.of(7).collect(collectingAndThen(toImmutableList(), ImmutableList::isEmpty)),
|
||||
Stream.of(8).collect(collectingAndThen(toImmutableMap(k -> k, v -> v), Map::isEmpty)),
|
||||
Stream.of(9)
|
||||
.collect(collectingAndThen(toImmutableMap(k -> k, v -> v), ImmutableMap::isEmpty)));
|
||||
Stream.of(5).collect(toImmutableSet()).isEmpty());
|
||||
}
|
||||
|
||||
ImmutableSet<Boolean> testStreamIsNotEmpty() {
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
package tech.picnic.errorprone.refasterrules;
|
||||
|
||||
import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
import static com.google.common.collect.ImmutableMap.toImmutableMap;
|
||||
import static com.google.common.collect.ImmutableSet.toImmutableSet;
|
||||
import static java.util.Comparator.comparingInt;
|
||||
import static java.util.Comparator.naturalOrder;
|
||||
import static java.util.Comparator.reverseOrder;
|
||||
import static java.util.function.Function.identity;
|
||||
import static java.util.function.Predicate.not;
|
||||
import static java.util.stream.Collectors.collectingAndThen;
|
||||
import static java.util.stream.Collectors.counting;
|
||||
import static java.util.stream.Collectors.filtering;
|
||||
import static java.util.stream.Collectors.flatMapping;
|
||||
@@ -25,15 +22,12 @@ import static java.util.stream.Collectors.summingInt;
|
||||
import static java.util.stream.Collectors.summingLong;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Streams;
|
||||
import java.util.Arrays;
|
||||
import java.util.DoubleSummaryStatistics;
|
||||
import java.util.IntSummaryStatistics;
|
||||
import java.util.List;
|
||||
import java.util.LongSummaryStatistics;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
@@ -46,12 +40,8 @@ final class StreamRulesTest implements RefasterRuleCollectionTestCase {
|
||||
public ImmutableSet<Object> elidedTypesAndStaticImports() {
|
||||
return ImmutableSet.of(
|
||||
ImmutableList.class,
|
||||
ImmutableMap.class,
|
||||
List.class,
|
||||
Map.class,
|
||||
Objects.class,
|
||||
Streams.class,
|
||||
collectingAndThen(null, null),
|
||||
counting(),
|
||||
filtering(null, null),
|
||||
flatMapping(null, null),
|
||||
@@ -66,9 +56,7 @@ final class StreamRulesTest implements RefasterRuleCollectionTestCase {
|
||||
summarizingLong(null),
|
||||
summingDouble(null),
|
||||
summingInt(null),
|
||||
summingLong(null),
|
||||
toImmutableList(),
|
||||
toImmutableMap(null, null));
|
||||
summingLong(null));
|
||||
}
|
||||
|
||||
String testJoining() {
|
||||
@@ -127,11 +115,7 @@ final class StreamRulesTest implements RefasterRuleCollectionTestCase {
|
||||
Stream.of(2).findAny().isEmpty(),
|
||||
Stream.of(3).findAny().isEmpty(),
|
||||
Stream.of(4).findAny().isEmpty(),
|
||||
Stream.of(5).findAny().isEmpty(),
|
||||
Stream.of(6).findAny().isEmpty(),
|
||||
Stream.of(7).findAny().isEmpty(),
|
||||
Stream.of(8).findAny().isEmpty(),
|
||||
Stream.of(9).findAny().isEmpty());
|
||||
Stream.of(5).findAny().isEmpty());
|
||||
}
|
||||
|
||||
ImmutableSet<Boolean> testStreamIsNotEmpty() {
|
||||
|
||||
@@ -73,18 +73,6 @@ final class StringRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return Objects.toString("foo");
|
||||
}
|
||||
|
||||
ImmutableSet<String> testNewStringFromCharArraySubSequence() {
|
||||
return ImmutableSet.of(
|
||||
String.valueOf(new char[] {'f', 'o', 'o'}, 0, 1),
|
||||
String.copyValueOf(new char[] {'b', 'a', 'r'}, 2, 3));
|
||||
}
|
||||
|
||||
ImmutableSet<String> testNewStringFromCharArray() {
|
||||
return ImmutableSet.of(
|
||||
String.valueOf(new char[] {'f', 'o', 'o'}),
|
||||
new String(new char[] {'b', 'a', 'r'}, 0, new char[] {'b', 'a', 'r'}.length));
|
||||
}
|
||||
|
||||
Function<Object, String> testStringValueOfMethodReference() {
|
||||
return Objects::toString;
|
||||
}
|
||||
|
||||
@@ -75,16 +75,6 @@ final class StringRulesTest implements RefasterRuleCollectionTestCase {
|
||||
return String.valueOf("foo");
|
||||
}
|
||||
|
||||
ImmutableSet<String> testNewStringFromCharArraySubSequence() {
|
||||
return ImmutableSet.of(
|
||||
new String(new char[] {'f', 'o', 'o'}, 0, 1), new String(new char[] {'b', 'a', 'r'}, 2, 3));
|
||||
}
|
||||
|
||||
ImmutableSet<String> testNewStringFromCharArray() {
|
||||
return ImmutableSet.of(
|
||||
new String(new char[] {'f', 'o', 'o'}), new String(new char[] {'b', 'a', 'r'}));
|
||||
}
|
||||
|
||||
Function<Object, String> testStringValueOfMethodReference() {
|
||||
return String::valueOf;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>tech.picnic.error-prone-support</groupId>
|
||||
<artifactId>error-prone-support</artifactId>
|
||||
<version>0.15.0</version>
|
||||
<version>0.14.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>error-prone-experimental</artifactId>
|
||||
@@ -20,11 +20,6 @@
|
||||
<artifactId>error_prone_annotation</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${groupId.error-prone}</groupId>
|
||||
<artifactId>error_prone_annotations</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${groupId.error-prone}</groupId>
|
||||
<artifactId>error_prone_check_api</artifactId>
|
||||
@@ -50,11 +45,6 @@
|
||||
<artifactId>guava</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jspecify</groupId>
|
||||
<artifactId>jspecify</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
/** Experimental Error Prone checks. */
|
||||
@com.google.errorprone.annotations.CheckReturnValue
|
||||
@org.jspecify.annotations.NullMarked
|
||||
package tech.picnic.errorprone.experimental.bugpatterns;
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>tech.picnic.error-prone-support</groupId>
|
||||
<artifactId>error-prone-support</artifactId>
|
||||
<version>0.15.0</version>
|
||||
<version>0.14.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>error-prone-guidelines</artifactId>
|
||||
@@ -53,16 +53,6 @@
|
||||
<artifactId>error-prone-utils</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>refaster-support</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.auto</groupId>
|
||||
<artifactId>auto-common</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.auto.service</groupId>
|
||||
<artifactId>auto-service-annotations</artifactId>
|
||||
|
||||
@@ -1,231 +0,0 @@
|
||||
package tech.picnic.errorprone.guidelines.bugpatterns;
|
||||
|
||||
import static com.google.common.base.Verify.verify;
|
||||
import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
import static com.google.errorprone.BugPattern.LinkType.CUSTOM;
|
||||
import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
|
||||
import static com.google.errorprone.BugPattern.StandardTags.LIKELY_ERROR;
|
||||
import static com.google.errorprone.matchers.ChildMultiMatcher.MatchType.AT_LEAST_ONE;
|
||||
import static com.google.errorprone.matchers.Matchers.annotations;
|
||||
import static com.google.errorprone.matchers.Matchers.isType;
|
||||
import static java.util.Comparator.comparing;
|
||||
import static java.util.stream.Collectors.toCollection;
|
||||
import static tech.picnic.errorprone.utils.Documentation.BUG_PATTERNS_BASE_URL;
|
||||
|
||||
import com.google.auto.common.AnnotationMirrors;
|
||||
import com.google.auto.service.AutoService;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Streams;
|
||||
import com.google.errorprone.BugPattern;
|
||||
import com.google.errorprone.VisitorState;
|
||||
import com.google.errorprone.bugpatterns.BugChecker;
|
||||
import com.google.errorprone.bugpatterns.BugChecker.ClassTreeMatcher;
|
||||
import com.google.errorprone.fixes.SuggestedFixes;
|
||||
import com.google.errorprone.matchers.Description;
|
||||
import com.google.errorprone.matchers.MultiMatcher;
|
||||
import com.google.errorprone.matchers.MultiMatcher.MultiMatchResult;
|
||||
import com.google.errorprone.refaster.annotation.BeforeTemplate;
|
||||
import com.google.errorprone.util.ASTHelpers;
|
||||
import com.google.errorprone.util.Signatures;
|
||||
import com.sun.source.tree.AnnotationTree;
|
||||
import com.sun.source.tree.ClassTree;
|
||||
import com.sun.source.tree.MethodInvocationTree;
|
||||
import com.sun.source.tree.MethodTree;
|
||||
import com.sun.source.tree.NewClassTree;
|
||||
import com.sun.source.tree.Tree;
|
||||
import com.sun.source.util.TreeScanner;
|
||||
import com.sun.tools.javac.code.Attribute;
|
||||
import com.sun.tools.javac.code.Symbol.ClassSymbol;
|
||||
import com.sun.tools.javac.code.Symbol.MethodSymbol;
|
||||
import com.sun.tools.javac.code.Symbol.TypeSymbol;
|
||||
import com.sun.tools.javac.util.Constants;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
import javax.lang.model.element.AnnotationMirror;
|
||||
import javax.lang.model.element.AnnotationValue;
|
||||
import javax.lang.model.element.Modifier;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* A {@link BugChecker} that validates the claim made by {@link
|
||||
* tech.picnic.errorprone.refaster.annotation.TypeMigration} annotations.
|
||||
*/
|
||||
// XXX: As-is this checker assumes that a method is fully migrated if it is invoked inside at least
|
||||
// one `@BeforeTemplate` method. A stronger check would be to additionally verify that:
|
||||
// 1. Such invocations are not conditionally matched. That is, there should be no constraint on
|
||||
// their context (i.e. any surrounding code), and their parameters must be `@BeforeTemplate`
|
||||
// method parameters with types that are not more restrictive than those of the method itself.
|
||||
// Additionally, the result of non-void methods should be "returned" by the `@BeforeTemplate`
|
||||
// method, so that Refaster will match any expression, rather than just statements. (One caveat
|
||||
// with this "context-independent migrations only" approach is that APIs often expose methods
|
||||
// that are only useful in combination with other methods of the API; insisting that such methods
|
||||
// are migrated in isolation is unreasonable.)
|
||||
// 2. Where relevant, method references should also be migrated. (TBD what "relevant" means in this
|
||||
// case, and whether in fact method reference matchers can be _derived_ from the associated
|
||||
// method invocation matchers.)
|
||||
// XXX: This checker currently does no concern itself with public fields. Consider adding support
|
||||
// for those.
|
||||
@AutoService(BugChecker.class)
|
||||
@BugPattern(
|
||||
summary =
|
||||
"The set of unmigrated methods listed by the `@TypeMigration` annotation must be minimal "
|
||||
+ "yet exhaustive",
|
||||
link = BUG_PATTERNS_BASE_URL + "ExhaustiveRefasterTypeMigration",
|
||||
linkType = CUSTOM,
|
||||
severity = WARNING,
|
||||
tags = LIKELY_ERROR)
|
||||
public final class ExhaustiveRefasterTypeMigration extends BugChecker implements ClassTreeMatcher {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final MultiMatcher<Tree, AnnotationTree> IS_TYPE_MIGRATION =
|
||||
annotations(AT_LEAST_ONE, isType("tech.picnic.errorprone.refaster.annotation.TypeMigration"));
|
||||
private static final MultiMatcher<Tree, AnnotationTree> HAS_BEFORE_TEMPLATE =
|
||||
annotations(AT_LEAST_ONE, isType(BeforeTemplate.class.getCanonicalName()));
|
||||
private static final String TYPE_MIGRATION_TYPE_ELEMENT = "of";
|
||||
private static final String TYPE_MIGRATION_UNMIGRATED_METHODS_ELEMENT = "unmigratedMethods";
|
||||
|
||||
/** Instantiates a new {@link ExhaustiveRefasterTypeMigration} instance. */
|
||||
public ExhaustiveRefasterTypeMigration() {}
|
||||
|
||||
@Override
|
||||
public Description matchClass(ClassTree tree, VisitorState state) {
|
||||
MultiMatchResult<AnnotationTree> migrationAnnotations =
|
||||
IS_TYPE_MIGRATION.multiMatchResult(tree, state);
|
||||
if (!migrationAnnotations.matches()) {
|
||||
return Description.NO_MATCH;
|
||||
}
|
||||
|
||||
AnnotationTree migrationAnnotation = migrationAnnotations.onlyMatchingNode();
|
||||
AnnotationMirror annotationMirror = ASTHelpers.getAnnotationMirror(migrationAnnotation);
|
||||
TypeSymbol migratedType = getMigratedType(annotationMirror);
|
||||
if (migratedType.asType().isPrimitive() || !(migratedType instanceof ClassSymbol)) {
|
||||
return buildDescription(migrationAnnotation)
|
||||
.setMessage(String.format("Migration of type '%s' is unsupported", migratedType))
|
||||
.build();
|
||||
}
|
||||
|
||||
ImmutableList<String> methodsClaimedUnmigrated = getMethodsClaimedUnmigrated(annotationMirror);
|
||||
ImmutableList<String> unmigratedMethods =
|
||||
getMethodsDefinitelyUnmigrated(
|
||||
tree, (ClassSymbol) migratedType, signatureOrder(methodsClaimedUnmigrated), state);
|
||||
|
||||
if (unmigratedMethods.equals(methodsClaimedUnmigrated)) {
|
||||
return Description.NO_MATCH;
|
||||
}
|
||||
|
||||
/*
|
||||
* The `@TypeMigration` annotation lists a different set of unmigrated methods than the one
|
||||
* produced by our analysis; suggest a replacement.
|
||||
*/
|
||||
// XXX: `updateAnnotationArgumentValues` will prepend the new attribute argument if it is not
|
||||
// already present. It would be nicer if it _appended_ the new attribute.
|
||||
return describeMatch(
|
||||
migrationAnnotation,
|
||||
SuggestedFixes.updateAnnotationArgumentValues(
|
||||
migrationAnnotation,
|
||||
state,
|
||||
TYPE_MIGRATION_UNMIGRATED_METHODS_ELEMENT,
|
||||
unmigratedMethods.stream().map(Constants::format).collect(toImmutableList()))
|
||||
.build());
|
||||
}
|
||||
|
||||
private static TypeSymbol getMigratedType(AnnotationMirror migrationAnnotation) {
|
||||
AnnotationValue value =
|
||||
AnnotationMirrors.getAnnotationValue(migrationAnnotation, TYPE_MIGRATION_TYPE_ELEMENT);
|
||||
verify(
|
||||
value instanceof Attribute.Class,
|
||||
"Value of annotation element `%s` is '%s' rather than a class",
|
||||
TYPE_MIGRATION_TYPE_ELEMENT,
|
||||
value);
|
||||
return ((Attribute.Class) value).classType.tsym;
|
||||
}
|
||||
|
||||
private static ImmutableList<String> getMethodsClaimedUnmigrated(
|
||||
AnnotationMirror migrationAnnotation) {
|
||||
AnnotationValue value =
|
||||
AnnotationMirrors.getAnnotationValue(
|
||||
migrationAnnotation, TYPE_MIGRATION_UNMIGRATED_METHODS_ELEMENT);
|
||||
verify(
|
||||
value instanceof Attribute.Array,
|
||||
"Value of annotation element `%s` is '%s' rather than an array",
|
||||
TYPE_MIGRATION_UNMIGRATED_METHODS_ELEMENT,
|
||||
value);
|
||||
return ((Attribute.Array) value)
|
||||
.getValue().stream().map(a -> a.getValue().toString()).collect(toImmutableList());
|
||||
}
|
||||
|
||||
// XXX: Once only JDK 14 and above are supported, change the
|
||||
// `m.getModifiers().contains(Modifier.PUBLIC)` check to just `m.isPublic()`.
|
||||
private static ImmutableList<String> getMethodsDefinitelyUnmigrated(
|
||||
ClassTree tree, ClassSymbol migratedType, Comparator<String> comparator, VisitorState state) {
|
||||
Set<MethodSymbol> publicMethods =
|
||||
Streams.stream(
|
||||
ASTHelpers.scope(migratedType.members())
|
||||
.getSymbols(
|
||||
m ->
|
||||
m.getModifiers().contains(Modifier.PUBLIC)
|
||||
&& m instanceof MethodSymbol))
|
||||
.map(MethodSymbol.class::cast)
|
||||
.collect(toCollection(HashSet::new));
|
||||
|
||||
/* Remove methods that *appear* to be migrated. Note that this is an imperfect heuristic. */
|
||||
removeMethodsInvokedInBeforeTemplateMethods(tree, publicMethods, state);
|
||||
|
||||
return publicMethods.stream()
|
||||
.map(m -> Signatures.prettyMethodSignature(migratedType, m))
|
||||
.sorted(comparator)
|
||||
.collect(toImmutableList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link Comparator} that orders method signatures to match the given list of
|
||||
* signatures, with any signatures not listed ordered first, lexicographically.
|
||||
*
|
||||
* @implNote This method does not use {@code comparing(list::indexOf)}, as that would make each
|
||||
* comparison a linear, rather than constant-time operation.
|
||||
*/
|
||||
private static Comparator<String> signatureOrder(ImmutableList<String> existingOrder) {
|
||||
Map<String, Integer> knownEntries = new HashMap<>();
|
||||
for (int i = 0; i < existingOrder.size(); i++) {
|
||||
knownEntries.putIfAbsent(existingOrder.get(i), i);
|
||||
}
|
||||
|
||||
// XXX: The lexicographical order applied to unknown entries aims to match the order applied by
|
||||
// the `LexicographicalAnnotationAttributeListing` check; consider deduplicating this logic.
|
||||
return comparing((String v) -> knownEntries.getOrDefault(v, -1))
|
||||
.thenComparing(String.CASE_INSENSITIVE_ORDER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes from the given set of {@link MethodSymbol}s the ones that refer to a method that is
|
||||
* invoked inside a {@link com.google.errorprone.refaster.annotation.BeforeTemplate} method inside
|
||||
* the specified {@link ClassTree}.
|
||||
*/
|
||||
private static void removeMethodsInvokedInBeforeTemplateMethods(
|
||||
ClassTree tree, Set<MethodSymbol> candidates, VisitorState state) {
|
||||
new TreeScanner<@Nullable Void, Consumer<MethodSymbol>>() {
|
||||
@Override
|
||||
public @Nullable Void visitMethod(MethodTree tree, Consumer<MethodSymbol> sink) {
|
||||
return HAS_BEFORE_TEMPLATE.matches(tree, state)
|
||||
? super.visitMethod(tree, candidates::remove)
|
||||
: null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Void visitNewClass(NewClassTree tree, Consumer<MethodSymbol> sink) {
|
||||
sink.accept(ASTHelpers.getSymbol(tree));
|
||||
return super.visitNewClass(tree, sink);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Void visitMethodInvocation(
|
||||
MethodInvocationTree tree, Consumer<MethodSymbol> sink) {
|
||||
sink.accept(ASTHelpers.getSymbol(tree));
|
||||
return super.visitMethodInvocation(tree, sink);
|
||||
}
|
||||
}.scan(tree, s -> {});
|
||||
}
|
||||
}
|
||||
@@ -1,263 +0,0 @@
|
||||
package tech.picnic.errorprone.guidelines.bugpatterns;
|
||||
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper;
|
||||
import com.google.errorprone.BugCheckerRefactoringTestHelper.TestMode;
|
||||
import com.google.errorprone.CompilationTestHelper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
final class ExhaustiveRefasterTypeMigrationTest {
|
||||
@Test
|
||||
void identification() {
|
||||
CompilationTestHelper.newInstance(ExhaustiveRefasterTypeMigration.class, getClass())
|
||||
.addSourceLines(
|
||||
"Util.java",
|
||||
"class Util {",
|
||||
" public static int CONSTANT = 42;",
|
||||
"",
|
||||
" public static void publicStaticVoidMethod() {}",
|
||||
"",
|
||||
" static void packagePrivateStaticVoidMethod() {}",
|
||||
"",
|
||||
" protected static void protectedStaticVoidMethod() {}",
|
||||
"",
|
||||
" private static void privateStaticVoidMethod() {}",
|
||||
"",
|
||||
" public static int publicStaticIntMethod2() {",
|
||||
" return 0;",
|
||||
" }",
|
||||
"",
|
||||
" public String publicStringMethodWithArg(int arg) {",
|
||||
" return String.valueOf(arg);",
|
||||
" }",
|
||||
"}")
|
||||
.addSourceLines(
|
||||
"A.java",
|
||||
"import com.google.errorprone.refaster.annotation.AfterTemplate;",
|
||||
"import com.google.errorprone.refaster.annotation.BeforeTemplate;",
|
||||
"import tech.picnic.errorprone.refaster.annotation.TypeMigration;",
|
||||
"",
|
||||
"class A {",
|
||||
" class UnannotatedEmptyClass {}",
|
||||
"",
|
||||
" // BUG: Diagnostic contains: Migration of type 'int' is unsupported",
|
||||
" @TypeMigration(of = int.class)",
|
||||
" class AnnotatedWithPrimitive {}",
|
||||
"",
|
||||
" @TypeMigration(",
|
||||
" of = Util.class,",
|
||||
" unmigratedMethods = {",
|
||||
" \"publicStaticIntMethod2()\",",
|
||||
" \"publicStringMethodWithArg(int)\",",
|
||||
" \"publicStaticVoidMethod()\"",
|
||||
" })",
|
||||
" class AnnotatedEmptyClass {}",
|
||||
"",
|
||||
" @TypeMigration(",
|
||||
" of = Util.class,",
|
||||
" unmigratedMethods = {",
|
||||
" \"publicStaticVoidMethod()\",",
|
||||
" \"publicStringMethodWithArg(int)\",",
|
||||
" \"publicStaticIntMethod2()\"",
|
||||
" })",
|
||||
" class AnnotatedEmptyClassWithUnsortedMethodListing {}",
|
||||
"",
|
||||
" class UnannotatedTemplate {",
|
||||
" @BeforeTemplate",
|
||||
" void before(int value) {",
|
||||
" Util.publicStaticVoidMethod();",
|
||||
" Util.publicStaticIntMethod2();",
|
||||
" new Util().publicStringMethodWithArg(value);",
|
||||
" }",
|
||||
" }",
|
||||
"",
|
||||
" @TypeMigration(",
|
||||
" of = Util.class,",
|
||||
" unmigratedMethods = {",
|
||||
" \"publicStaticIntMethod2()\",",
|
||||
" \"publicStringMethodWithArg(int)\",",
|
||||
" \"publicStaticVoidMethod()\"",
|
||||
" })",
|
||||
" class AnnotatedWithoutBeforeTemplate {",
|
||||
" {",
|
||||
" Util.publicStaticIntMethod2();",
|
||||
" }",
|
||||
"",
|
||||
" @AfterTemplate",
|
||||
" void after(int value) {",
|
||||
" Util.publicStaticVoidMethod();",
|
||||
" new Util().publicStringMethodWithArg(value);",
|
||||
" }",
|
||||
" }",
|
||||
"",
|
||||
" @TypeMigration(of = Util.class)",
|
||||
" class AnnotatedFullyMigrated {",
|
||||
" @BeforeTemplate",
|
||||
" void before() {",
|
||||
" new Util().publicStringMethodWithArg(Util.publicStaticIntMethod2());",
|
||||
" }",
|
||||
"",
|
||||
" @BeforeTemplate",
|
||||
" void before2() {",
|
||||
" Util.publicStaticVoidMethod();",
|
||||
" }",
|
||||
" }",
|
||||
"",
|
||||
" @TypeMigration(of = Util.class, unmigratedMethods = \"publicStringMethodWithArg(int)\")",
|
||||
" class AnnotatedPartiallyMigrated {",
|
||||
" @BeforeTemplate",
|
||||
" void before() {",
|
||||
" Util.publicStaticVoidMethod();",
|
||||
" Util.publicStaticIntMethod2();",
|
||||
" }",
|
||||
" }",
|
||||
"",
|
||||
" // BUG: Diagnostic contains: The set of unmigrated methods listed by the `@TypeMigration`",
|
||||
" // annotation must be minimal yet exhaustive",
|
||||
" @TypeMigration(of = Util.class, unmigratedMethods = \"publicStringMethodWithArg(int)\")",
|
||||
" class AnnotatedWithIncompleteMethodListing {",
|
||||
" @BeforeTemplate",
|
||||
" void before() {",
|
||||
" Util.publicStaticIntMethod2();",
|
||||
" }",
|
||||
" }",
|
||||
"",
|
||||
" // BUG: Diagnostic contains: The set of unmigrated methods listed by the `@TypeMigration`",
|
||||
" // annotation must be minimal yet exhaustive",
|
||||
" @TypeMigration(",
|
||||
" of = Util.class,",
|
||||
" unmigratedMethods = {\"publicStaticIntMethod2()\", \"publicStringMethodWithArg(int)\"})",
|
||||
" class AnnotatedWithMigratedMethodReference {",
|
||||
" @BeforeTemplate",
|
||||
" void before() {",
|
||||
" Util.publicStaticVoidMethod();",
|
||||
" Util.publicStaticIntMethod2();",
|
||||
" }",
|
||||
" }",
|
||||
"",
|
||||
" // BUG: Diagnostic contains: The set of unmigrated methods listed by the `@TypeMigration`",
|
||||
" // annotation must be minimal yet exhaustive",
|
||||
" @TypeMigration(",
|
||||
" of = Util.class,",
|
||||
" unmigratedMethods = {\"extra\", \"publicStringMethodWithArg(int)\"})",
|
||||
" class AnnotatedWithUnknownMethodReference {",
|
||||
" @BeforeTemplate",
|
||||
" void before() {",
|
||||
" Util.publicStaticVoidMethod();",
|
||||
" Util.publicStaticIntMethod2();",
|
||||
" }",
|
||||
" }",
|
||||
"}")
|
||||
.doTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
void replacement() {
|
||||
BugCheckerRefactoringTestHelper.newInstance(ExhaustiveRefasterTypeMigration.class, getClass())
|
||||
.addInputLines(
|
||||
"Util.java",
|
||||
"public final class Util {",
|
||||
" public static void publicStaticVoidMethod() {}",
|
||||
"",
|
||||
" public static int publicStaticIntMethod2() {",
|
||||
" return 0;",
|
||||
" }",
|
||||
"",
|
||||
" public String publicStringMethodWithArg(int arg) {",
|
||||
" return String.valueOf(arg);",
|
||||
" }",
|
||||
"",
|
||||
" public String publicStringMethodWithArg(String arg) {",
|
||||
" return arg;",
|
||||
" }",
|
||||
"}")
|
||||
.expectUnchanged()
|
||||
.addInputLines(
|
||||
"A.java",
|
||||
"import com.google.errorprone.refaster.annotation.BeforeTemplate;",
|
||||
"import tech.picnic.errorprone.refaster.annotation.TypeMigration;",
|
||||
"",
|
||||
"class A {",
|
||||
" @TypeMigration(of = Util.class)",
|
||||
" class AnnotatedWithoutMethodListing {",
|
||||
" {",
|
||||
" new Util().publicStringMethodWithArg(1);",
|
||||
" }",
|
||||
"",
|
||||
" @BeforeTemplate",
|
||||
" void before() {",
|
||||
" Util.publicStaticIntMethod2();",
|
||||
" }",
|
||||
" }",
|
||||
"",
|
||||
" @TypeMigration(",
|
||||
" of = Util.class,",
|
||||
" unmigratedMethods = {\"publicStaticIntMethod2()\", \"extra\", \"publicStringMethodWithArg(int)\"})",
|
||||
" class AnnotatedWithIncorrectMethodReference {",
|
||||
" @BeforeTemplate",
|
||||
" void before() {",
|
||||
" new Util().publicStringMethodWithArg(\"1\");",
|
||||
" Util.publicStaticVoidMethod();",
|
||||
" Util.publicStaticIntMethod2();",
|
||||
" }",
|
||||
" }",
|
||||
"",
|
||||
" @TypeMigration(",
|
||||
" of = Util.class,",
|
||||
" unmigratedMethods = {\"publicStaticVoidMethod()\", \"publicStaticVoidMethod()\"})",
|
||||
" class AnnotatedWithDuplicateMethodReference {",
|
||||
" @BeforeTemplate",
|
||||
" void before() {",
|
||||
" new Util().publicStringMethodWithArg(1);",
|
||||
" new Util().publicStringMethodWithArg(\"1\");",
|
||||
" Util.publicStaticIntMethod2();",
|
||||
" }",
|
||||
" }",
|
||||
"}")
|
||||
.addOutputLines(
|
||||
"A.java",
|
||||
"import com.google.errorprone.refaster.annotation.BeforeTemplate;",
|
||||
"import tech.picnic.errorprone.refaster.annotation.TypeMigration;",
|
||||
"",
|
||||
"class A {",
|
||||
" @TypeMigration(",
|
||||
" unmigratedMethods = {",
|
||||
" \"publicStaticVoidMethod()\",",
|
||||
" \"publicStringMethodWithArg(int)\",",
|
||||
" \"publicStringMethodWithArg(String)\",",
|
||||
" \"Util()\"",
|
||||
" },",
|
||||
" of = Util.class)",
|
||||
" class AnnotatedWithoutMethodListing {",
|
||||
" {",
|
||||
" new Util().publicStringMethodWithArg(1);",
|
||||
" }",
|
||||
"",
|
||||
" @BeforeTemplate",
|
||||
" void before() {",
|
||||
" Util.publicStaticIntMethod2();",
|
||||
" }",
|
||||
" }",
|
||||
"",
|
||||
" @TypeMigration(of = Util.class, unmigratedMethods = \"publicStringMethodWithArg(int)\")",
|
||||
" class AnnotatedWithIncorrectMethodReference {",
|
||||
" @BeforeTemplate",
|
||||
" void before() {",
|
||||
" new Util().publicStringMethodWithArg(\"1\");",
|
||||
" Util.publicStaticVoidMethod();",
|
||||
" Util.publicStaticIntMethod2();",
|
||||
" }",
|
||||
" }",
|
||||
"",
|
||||
" @TypeMigration(of = Util.class, unmigratedMethods = \"publicStaticVoidMethod()\")",
|
||||
" class AnnotatedWithDuplicateMethodReference {",
|
||||
" @BeforeTemplate",
|
||||
" void before() {",
|
||||
" new Util().publicStringMethodWithArg(1);",
|
||||
" new Util().publicStringMethodWithArg(\"1\");",
|
||||
" Util.publicStaticIntMethod2();",
|
||||
" }",
|
||||
" }",
|
||||
"}")
|
||||
.doTest(TestMode.TEXT_MATCH);
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>tech.picnic.error-prone-support</groupId>
|
||||
<artifactId>error-prone-support</artifactId>
|
||||
<version>0.15.0</version>
|
||||
<version>0.14.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>error-prone-utils</artifactId>
|
||||
|
||||
6
pom.xml
6
pom.xml
@@ -4,7 +4,7 @@
|
||||
|
||||
<groupId>tech.picnic.error-prone-support</groupId>
|
||||
<artifactId>error-prone-support</artifactId>
|
||||
<version>0.15.0</version>
|
||||
<version>0.14.1-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<name>Picnic :: Error Prone Support</name>
|
||||
@@ -52,7 +52,7 @@
|
||||
|
||||
<scm child.scm.developerConnection.inherit.append.path="false" child.scm.url.inherit.append.path="false">
|
||||
<developerConnection>scm:git:git@github.com:PicnicSupermarket/error-prone-support.git</developerConnection>
|
||||
<tag>v0.15.0</tag>
|
||||
<tag>HEAD</tag>
|
||||
<url>https://github.com/PicnicSupermarket/error-prone-support</url>
|
||||
</scm>
|
||||
<issueManagement>
|
||||
@@ -148,7 +148,7 @@
|
||||
<groupId.error-prone>com.google.errorprone</groupId.error-prone>
|
||||
<!-- The build timestamp is derived from the most recent commit
|
||||
timestamp in support of reproducible builds. -->
|
||||
<project.build.outputTimestamp>2024-02-11T13:28:00Z</project.build.outputTimestamp>
|
||||
<project.build.outputTimestamp>${git.commit.time}</project.build.outputTimestamp>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<!-- Glob pattern identifying Refaster rule definition files. These
|
||||
Java classes don't contain "regular" code, and thus require special
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>tech.picnic.error-prone-support</groupId>
|
||||
<artifactId>error-prone-support</artifactId>
|
||||
<version>0.15.0</version>
|
||||
<version>0.14.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>refaster-compiler</artifactId>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>tech.picnic.error-prone-support</groupId>
|
||||
<artifactId>error-prone-support</artifactId>
|
||||
<version>0.15.0</version>
|
||||
<version>0.14.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>refaster-runner</artifactId>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>tech.picnic.error-prone-support</groupId>
|
||||
<artifactId>error-prone-support</artifactId>
|
||||
<version>0.15.0</version>
|
||||
<version>0.14.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>refaster-support</artifactId>
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
package tech.picnic.errorprone.refaster.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Indicates that a Refaster rule or group of Refaster rules is intended to migrate away from the
|
||||
* indicated type.
|
||||
*/
|
||||
// XXX: Add support for `#unmigratedFields()`.
|
||||
// XXX: Consider making this annotation `@Repeatable`, for cases where a single Refaster rule
|
||||
// collection migrates away from multiple types.
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@Target(ElementType.TYPE)
|
||||
public @interface TypeMigration {
|
||||
/**
|
||||
* The type migrated away from.
|
||||
*
|
||||
* @return The type generally used in the {@link
|
||||
* com.google.errorprone.refaster.annotation.BeforeTemplate} methods of annotated Refaster
|
||||
* rule(s).
|
||||
*/
|
||||
Class<?> of();
|
||||
|
||||
/**
|
||||
* The signatures of public methods and constructors that are not (yet) migrated by the annotated
|
||||
* Refaster rule(s).
|
||||
*
|
||||
* @return A possibly empty enumeration of method and constructor signatures, formatted according
|
||||
* to {@link
|
||||
* com.google.errorprone.util.Signatures#prettyMethodSignature(com.sun.tools.javac.code.Symbol.ClassSymbol,
|
||||
* com.sun.tools.javac.code.Symbol.MethodSymbol)}.
|
||||
*/
|
||||
String[] unmigratedMethods() default {};
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>tech.picnic.error-prone-support</groupId>
|
||||
<artifactId>error-prone-support</artifactId>
|
||||
<version>0.15.0</version>
|
||||
<version>0.14.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>refaster-test-support</artifactId>
|
||||
|
||||
Reference in New Issue
Block a user