diff --git a/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/RefasterMethodParameterOrder.java b/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/RefasterMethodParameterOrder.java new file mode 100644 index 0000000000..46575300b3 --- /dev/null +++ b/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/RefasterMethodParameterOrder.java @@ -0,0 +1,139 @@ +package tech.picnic.errorprone.bugpatterns; + +import static com.google.common.collect.ImmutableList.toImmutableList; +import static com.google.errorprone.BugPattern.LinkType.CUSTOM; +import static com.google.errorprone.BugPattern.SeverityLevel.SUGGESTION; +import static com.google.errorprone.BugPattern.StandardTags.STYLE; +import static com.google.errorprone.matchers.Matchers.anyOf; +import static com.google.errorprone.matchers.Matchers.hasAnnotation; +import static java.util.Comparator.comparing; +import static java.util.stream.Collectors.toCollection; +import static tech.picnic.errorprone.bugpatterns.util.Documentation.BUG_PATTERNS_BASE_URL; + +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.SuggestedFix; +import com.google.errorprone.matchers.Description; +import com.google.errorprone.matchers.Matcher; +import com.google.errorprone.refaster.annotation.AfterTemplate; +import com.google.errorprone.refaster.annotation.BeforeTemplate; +import com.google.errorprone.util.ASTHelpers; +import com.sun.source.tree.ClassTree; +import com.sun.source.tree.IdentifierTree; +import com.sun.source.tree.MethodTree; +import com.sun.source.tree.Tree; +import com.sun.source.tree.VariableTree; +import com.sun.source.util.TreeScanner; +import com.sun.tools.javac.code.Symbol; +import java.util.Comparator; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Stream; +import javax.lang.model.element.Name; +import org.jspecify.annotations.Nullable; +import tech.picnic.errorprone.bugpatterns.util.SourceCode; + +/** + * A {@link BugChecker} that flags Refaster methods with a non-canonical parameter order. + * + *
To a first approximation, parameters should be ordered by their first usage in an
+ * {@code @AfterTemplate} method. Ties are broken by preferring the order dictated by methods with a
+ * larger number of parameters.
+ */
+// XXX: This check can introduce suggestions that are incompatible with Error Prone's
+// `InconsistentOverloads` check. Review whether/how to improve this.
+@AutoService(BugChecker.class)
+@BugPattern(
+ summary = "Refaster template parameters should be listed in a canonical order",
+ link = BUG_PATTERNS_BASE_URL + "RefasterMethodParameterOrder",
+ linkType = CUSTOM,
+ severity = SUGGESTION,
+ tags = STYLE)
+public final class RefasterMethodParameterOrder extends BugChecker implements ClassTreeMatcher {
+ private static final long serialVersionUID = 1L;
+ private static final Matcher {
@BeforeTemplate
IterableAssert stream, Collector> collector, Iterable iterable) {
+ Stream stream, Iterable iterable, Collector> collector) {
return assertThat(stream.collect(collector)).containsAnyElementsOf(iterable);
}
@BeforeTemplate
ListAssert stream, Collector> collector, Iterable iterable) {
+ Stream stream, Iterable iterable, Collector> collector) {
return assertThat(stream.collect(collector)).containsAnyElementsOf(iterable);
}
@@ -551,13 +551,13 @@ ListAssert after(Stream stream, Iterable iterable) {
static final class AssertThatStreamContainsAnyOf {
@BeforeTemplate
IterableAssert stream, Collector> collector, U[] array) {
+ Stream stream, U[] array, Collector> collector) {
return assertThat(stream.collect(collector)).containsAnyOf(array);
}
@BeforeTemplate
ListAssert stream, Collector> collector, U[] array) {
+ Stream stream, U[] array, Collector> collector) {
return assertThat(stream.collect(collector)).containsAnyOf(array);
}
@@ -573,14 +573,14 @@ static final class AssertThatStreamContainsAnyOfVarArgs before(
- Stream stream, Collector> collector, @Repeated U elements) {
+ Stream stream, @Repeated U elements, Collector> collector) {
return assertThat(stream.collect(collector)).containsAnyOf(Refaster.asVarargs(elements));
}
@BeforeTemplate
@SuppressWarnings("AssertThatStreamContainsAnyOf" /* Varargs converted to array. */)
ListAssert stream, Collector> collector, @Repeated U elements) {
+ Stream stream, @Repeated U elements, Collector> collector) {
return assertThat(stream.collect(collector)).containsAnyOf(Refaster.asVarargs(elements));
}
@@ -596,13 +596,13 @@ ListAssert after(Stream stream, @Repeated U elements) {
static final class AssertThatStreamContainsAll {
@BeforeTemplate
IterableAssert stream, Collector> collector, Iterable iterable) {
+ Stream stream, Iterable iterable, Collector> collector) {
return assertThat(stream.collect(collector)).containsAll(iterable);
}
@BeforeTemplate
ListAssert stream, Collector> collector, Iterable iterable) {
+ Stream stream, Iterable iterable, Collector> collector) {
return assertThat(stream.collect(collector)).containsAll(iterable);
}
@@ -617,13 +617,13 @@ ListAssert after(Stream stream, Iterable iterable) {
static final class AssertThatStreamContains {
@BeforeTemplate
IterableAssert stream, Collector> collector, U[] array) {
+ Stream stream, U[] array, Collector> collector) {
return assertThat(stream.collect(collector)).contains(array);
}
@BeforeTemplate
ListAssert stream, Collector> collector, U[] array) {
+ Stream stream, U[] array, Collector> collector) {
return assertThat(stream.collect(collector)).contains(array);
}
@@ -639,14 +639,14 @@ static final class AssertThatStreamContainsVarArgs
@BeforeTemplate
@SuppressWarnings("AssertThatStreamContains" /* Varargs converted to array. */)
IterableAssert stream, Collector> collector, @Repeated U elements) {
+ Stream stream, @Repeated U elements, Collector> collector) {
return assertThat(stream.collect(collector)).contains(Refaster.asVarargs(elements));
}
@BeforeTemplate
@SuppressWarnings("AssertThatStreamContains" /* Varargs converted to array. */)
ListAssert stream, Collector> collector, @Repeated U elements) {
+ Stream stream, @Repeated U elements, Collector> collector) {
return assertThat(stream.collect(collector)).contains(Refaster.asVarargs(elements));
}
@@ -661,7 +661,7 @@ ListAssert after(Stream stream, @Repeated U elements) {
static final class AssertThatStreamContainsExactlyElementsOf {
@BeforeTemplate
ListAssert stream, Collector> collector, Iterable iterable) {
+ Stream stream, Iterable iterable, Collector> collector) {
return assertThat(stream.collect(collector)).containsExactlyElementsOf(iterable);
}
@@ -676,7 +676,7 @@ ListAssert after(Stream stream, Iterable iterable) {
static final class AssertThatStreamContainsExactly {
@BeforeTemplate
ListAssert stream, Collector> collector, U[] array) {
+ Stream stream, U[] array, Collector> collector) {
return assertThat(stream.collect(collector)).containsExactly(array);
}
@@ -692,7 +692,7 @@ static final class AssertThatStreamContainsExactlyVarargs before(
- Stream stream, Collector> collector, @Repeated U elements) {
+ Stream stream, @Repeated U elements, Collector> collector) {
return assertThat(stream.collect(collector)).containsExactly(Refaster.asVarargs(elements));
}
@@ -708,13 +708,13 @@ static final class AssertThatStreamContainsExactlyInAnyOrderElementsOf<
S, T extends S, U extends T> {
@BeforeTemplate
ListAssert stream, Collector> collector, Iterable iterable) {
+ Stream stream, Iterable iterable, Collector> collector) {
return assertThat(stream.collect(collector)).containsExactlyInAnyOrderElementsOf(iterable);
}
@BeforeTemplate
AbstractCollectionAssert, ?, T, ?> before2(
- Stream stream, Collector> collector, Iterable iterable) {
+ Stream stream, Iterable iterable, Collector> collector) {
return assertThat(stream.collect(collector)).containsExactlyInAnyOrderElementsOf(iterable);
}
@@ -729,13 +729,13 @@ ListAssert after(Stream stream, Iterable iterable) {
static final class AssertThatStreamContainsExactlyInAnyOrder {
@BeforeTemplate
ListAssert stream, Collector> collector, U[] array) {
+ Stream stream, U[] array, Collector> collector) {
return assertThat(stream.collect(collector)).containsExactlyInAnyOrder(array);
}
@BeforeTemplate
AbstractCollectionAssert, ?, T, ?> before2(
- Stream stream, Collector> collector, U[] array) {
+ Stream stream, U[] array, Collector> collector) {
return assertThat(stream.collect(collector)).containsExactlyInAnyOrder(array);
}
@@ -751,7 +751,7 @@ static final class AssertThatStreamContainsExactlyInAnyOrderVarArgs before(
- Stream stream, Collector> collector, @Repeated U elements) {
+ Stream stream, @Repeated U elements, Collector> collector) {
return assertThat(stream.collect(collector))
.containsExactlyInAnyOrder(Refaster.asVarargs(elements));
}
@@ -759,7 +759,7 @@ ListAssert stream, Collector> collector, @Repeated U elements) {
+ Stream stream, @Repeated U elements, Collector> collector) {
return assertThat(stream.collect(collector))
.containsExactlyInAnyOrder(Refaster.asVarargs(elements));
}
@@ -776,13 +776,13 @@ ListAssert after(Stream stream, @Repeated U elements) {
static final class AssertThatStreamContainsSequence {
@BeforeTemplate
ListAssert stream, Collector> collector, Iterable iterable) {
+ Stream stream, Iterable iterable, Collector> collector) {
return assertThat(stream.collect(collector)).containsSequence(iterable);
}
@BeforeTemplate
ListAssert stream, Collector> collector, U[] iterable) {
+ Stream stream, U[] iterable, Collector> collector) {
return assertThat(stream.collect(collector)).containsSequence(iterable);
}
@@ -798,7 +798,7 @@ static final class AssertThatStreamContainsSequenceVarArgs before(
- Stream stream, Collector> collector, @Repeated U elements) {
+ Stream stream, @Repeated U elements, Collector> collector) {
return assertThat(stream.collect(collector)).containsSequence(Refaster.asVarargs(elements));
}
@@ -814,13 +814,13 @@ ListAssert after(Stream stream, @Repeated U elements) {
static final class AssertThatStreamContainsSubsequence {
@BeforeTemplate
ListAssert stream, Collector> collector, Iterable iterable) {
+ Stream stream, Iterable iterable, Collector> collector) {
return assertThat(stream.collect(collector)).containsSubsequence(iterable);
}
@BeforeTemplate
ListAssert stream, Collector> collector, U[] iterable) {
+ Stream stream, U[] iterable, Collector> collector) {
return assertThat(stream.collect(collector)).containsSubsequence(iterable);
}
@@ -836,7 +836,7 @@ static final class AssertThatStreamContainsSubsequenceVarArgs before(
- Stream stream, Collector> collector, @Repeated U elements) {
+ Stream stream, @Repeated U elements, Collector> collector) {
return assertThat(stream.collect(collector))
.containsSubsequence(Refaster.asVarargs(elements));
}
@@ -853,13 +853,13 @@ ListAssert after(Stream stream, @Repeated U elements) {
static final class AssertThatStreamDoesNotContainAnyElementsOf {
@BeforeTemplate
IterableAssert stream, Collector> collector, Iterable iterable) {
+ Stream stream, Iterable iterable, Collector> collector) {
return assertThat(stream.collect(collector)).doesNotContainAnyElementsOf(iterable);
}
@BeforeTemplate
ListAssert stream, Collector> collector, Iterable iterable) {
+ Stream stream, Iterable iterable, Collector> collector) {
return assertThat(stream.collect(collector)).doesNotContainAnyElementsOf(iterable);
}
@@ -874,13 +874,13 @@ ListAssert after(Stream stream, Iterable iterable) {
static final class AssertThatStreamDoesNotContain {
@BeforeTemplate
IterableAssert stream, Collector> collector, U[] array) {
+ Stream stream, U[] array, Collector> collector) {
return assertThat(stream.collect(collector)).doesNotContain(array);
}
@BeforeTemplate
ListAssert stream, Collector> collector, U[] array) {
+ Stream stream, U[] array, Collector> collector) {
return assertThat(stream.collect(collector)).doesNotContain(array);
}
@@ -896,14 +896,14 @@ static final class AssertThatStreamDoesNotContainVarArgs before(
- Stream stream, Collector> collector, @Repeated U elements) {
+ Stream stream, @Repeated U elements, Collector> collector) {
return assertThat(stream.collect(collector)).doesNotContain(Refaster.asVarargs(elements));
}
@BeforeTemplate
@SuppressWarnings("AssertThatStreamDoesNotContain" /* Varargs converted to array. */)
ListAssert stream, Collector> collector, @Repeated U elements) {
+ Stream stream, @Repeated U elements, Collector> collector) {
return assertThat(stream.collect(collector)).doesNotContain(Refaster.asVarargs(elements));
}
@@ -918,13 +918,13 @@ ListAssert after(Stream stream, @Repeated U elements) {
static final class AssertThatStreamDoesNotContainSequence {
@BeforeTemplate
ListAssert stream, Collector> collector, Iterable iterable) {
+ Stream stream, Iterable iterable, Collector> collector) {
return assertThat(stream.collect(collector)).doesNotContainSequence(iterable);
}
@BeforeTemplate
ListAssert stream, Collector> collector, U[] iterable) {
+ Stream stream, U[] iterable, Collector> collector) {
return assertThat(stream.collect(collector)).doesNotContainSequence(iterable);
}
@@ -940,7 +940,7 @@ static final class AssertThatStreamDoesNotContainSequenceVarArgs before(
- Stream