Warning: this rewrite rule is not completely behavior preserving: while the
- * original code produces a set that iterates over the elements in encounter order, the
- * replacement code iterates over the elements in enum definition order.
- */
- // XXX: ^ Consider emitting a comment warning about this fact?
- static final class StreamToImmutableEnumSet> {
- @BeforeTemplate
- ImmutableSet before(Stream stream) {
- return stream.collect(toImmutableSet());
- }
-
- @AfterTemplate
- @UseImportPolicy(STATIC_IMPORT_ALWAYS)
- ImmutableSet after(Stream stream) {
- return stream.collect(toImmutableEnumSet());
- }
- }
-
/** Prefer {@link Iterators#getNext(Iterator, Object)} over more contrived alternatives. */
static final class IteratorGetNextOrDefault {
@BeforeTemplate
diff --git a/error-prone-contrib/src/main/java/tech/picnic/errorprone/refasterrules/ImmutableEnumSetRules.java b/error-prone-contrib/src/main/java/tech/picnic/errorprone/refasterrules/ImmutableEnumSetRules.java
new file mode 100644
index 0000000000..b7b40af650
--- /dev/null
+++ b/error-prone-contrib/src/main/java/tech/picnic/errorprone/refasterrules/ImmutableEnumSetRules.java
@@ -0,0 +1,246 @@
+package tech.picnic.errorprone.refasterrules;
+
+import static com.google.common.collect.ImmutableSet.toImmutableSet;
+import static com.google.common.collect.Sets.toImmutableEnumSet;
+import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Sets;
+import com.google.errorprone.refaster.Refaster;
+import com.google.errorprone.refaster.annotation.AfterTemplate;
+import com.google.errorprone.refaster.annotation.BeforeTemplate;
+import com.google.errorprone.refaster.annotation.Repeated;
+import com.google.errorprone.refaster.annotation.UseImportPolicy;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.EnumSet;
+import java.util.stream.Stream;
+import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation;
+
+/**
+ * Refaster rules related to expressions dealing with {@code
+ * com.google.common.collect.ImmutableEnumSet}s.
+ */
+// XXX: Some of the rules defined here impact iteration order. That's a rather subtle change. Should
+// we emit a comment warning about this fact? (This may produce a lot of noise. A bug checker could
+// in some cases determine whether iteration order is important.)
+// XXX: Consider replacing the `SetsImmutableEnumSet[N]` Refaster rules with a bug checker, such
+// that call to `ImmutableSet#of(Object, Object, Object, Object, Object, Object, Object[])` with
+// enum-typed values can also be rewritten.
+@OnlineDocumentation
+final class ImmutableEnumSetRules {
+ private ImmutableEnumSetRules() {}
+
+ /**
+ * Prefer {@link Sets#immutableEnumSet(Iterable)} for enum collections to take advantage of the
+ * internally used {@link EnumSet}.
+ *
+ *
Warning: this rule is not completely behavior preserving: while the
+ * original code produces a set that iterates over its elements in the same order as the input
+ * {@link Iterable}, the replacement code iterates over the elements in enum definition order.
+ */
+ static final class SetsImmutableEnumSetIterable> {
+ @BeforeTemplate
+ ImmutableSet before(Iterable elements) {
+ return ImmutableSet.copyOf(elements);
+ }
+
+ @BeforeTemplate
+ ImmutableSet before(Collection elements) {
+ return ImmutableSet.copyOf(elements);
+ }
+
+ @AfterTemplate
+ ImmutableSet after(Iterable elements) {
+ return Sets.immutableEnumSet(elements);
+ }
+ }
+
+ /**
+ * Prefer {@link Sets#immutableEnumSet(Iterable)} for enum collections to take advantage of the
+ * internally used {@link EnumSet}.
+ *
+ *
Warning: this rule is not completely behavior preserving: while the
+ * original code produces a set that iterates over its elements in the same order as defined in
+ * the array, the replacement code iterates over the elements in enum definition order.
+ */
+ static final class SetsImmutableEnumSetArraysAsList> {
+ @BeforeTemplate
+ ImmutableSet before(T[] elements) {
+ return ImmutableSet.copyOf(elements);
+ }
+
+ @AfterTemplate
+ ImmutableSet after(T[] elements) {
+ return Sets.immutableEnumSet(Arrays.asList(elements));
+ }
+ }
+
+ /**
+ * Prefer {@link Sets#immutableEnumSet(Enum, Enum[])} for enum collections to take advantage of
+ * the internally used {@link EnumSet}.
+ */
+ static final class SetsImmutableEnumSet1> {
+ @BeforeTemplate
+ @SuppressWarnings("SetsImmutableEnumSetIterable" /* This is a more specific template. */)
+ ImmutableSet before(T e1) {
+ return Refaster.anyOf(ImmutableSet.of(e1), ImmutableSet.copyOf(EnumSet.of(e1)));
+ }
+
+ @AfterTemplate
+ @SuppressWarnings("unchecked")
+ ImmutableSet after(T e1) {
+ return Sets.immutableEnumSet(e1);
+ }
+ }
+
+ /**
+ * Prefer {@link Sets#immutableEnumSet(Enum, Enum[])} for enum collections to take advantage of
+ * the internally used {@link EnumSet}.
+ *
+ *
Warning: this rule is not completely behavior preserving: while the {@link
+ * ImmutableSet#of} expression produces a set that iterates over its elements in the listed order,
+ * the replacement code iterates over the elements in enum definition order.
+ */
+ static final class SetsImmutableEnumSet2> {
+ @BeforeTemplate
+ @SuppressWarnings("SetsImmutableEnumSetIterable" /* This is a more specific template. */)
+ ImmutableSet before(T e1, T e2) {
+ return Refaster.anyOf(ImmutableSet.of(e1, e2), ImmutableSet.copyOf(EnumSet.of(e1, e2)));
+ }
+
+ @AfterTemplate
+ @SuppressWarnings("unchecked")
+ ImmutableSet after(T e1, T e2) {
+ return Sets.immutableEnumSet(e1, e2);
+ }
+ }
+
+ /**
+ * Prefer {@link Sets#immutableEnumSet(Enum, Enum[])} for enum collections to take advantage of
+ * the internally used {@link EnumSet}.
+ *
+ *
Warning: this rule is not completely behavior preserving: while the {@link
+ * ImmutableSet#of} expression produces a set that iterates over its elements in the listed order,
+ * the replacement code iterates over the elements in enum definition order.
+ */
+ static final class SetsImmutableEnumSet3> {
+ @BeforeTemplate
+ @SuppressWarnings("SetsImmutableEnumSetIterable" /* This is a more specific template. */)
+ ImmutableSet before(T e1, T e2, T e3) {
+ return Refaster.anyOf(
+ ImmutableSet.of(e1, e2, e3), ImmutableSet.copyOf(EnumSet.of(e1, e2, e3)));
+ }
+
+ @AfterTemplate
+ @SuppressWarnings("unchecked")
+ ImmutableSet after(T e1, T e2, T e3) {
+ return Sets.immutableEnumSet(e1, e2, e3);
+ }
+ }
+
+ /**
+ * Prefer {@link Sets#immutableEnumSet(Enum, Enum[])} for enum collections to take advantage of
+ * the internally used {@link EnumSet}.
+ *
+ *
Warning: this rule is not completely behavior preserving: while the {@link
+ * ImmutableSet#of} expression produces a set that iterates over its elements in the listed order,
+ * the replacement code iterates over the elements in enum definition order.
+ */
+ static final class SetsImmutableEnumSet4> {
+ @BeforeTemplate
+ @SuppressWarnings("SetsImmutableEnumSetIterable" /* This is a more specific template. */)
+ ImmutableSet before(T e1, T e2, T e3, T e4) {
+ return Refaster.anyOf(
+ ImmutableSet.of(e1, e2, e3, e4), ImmutableSet.copyOf(EnumSet.of(e1, e2, e3, e4)));
+ }
+
+ @AfterTemplate
+ @SuppressWarnings("unchecked")
+ ImmutableSet after(T e1, T e2, T e3, T e4) {
+ return Sets.immutableEnumSet(e1, e2, e3, e4);
+ }
+ }
+
+ /**
+ * Prefer {@link Sets#immutableEnumSet(Enum, Enum[])} for enum collections to take advantage of
+ * the internally used {@link EnumSet}.
+ *
+ *
Warning: this rule is not completely behavior preserving: while the {@link
+ * ImmutableSet#of} expression produces a set that iterates over its elements in the listed order,
+ * the replacement code iterates over the elements in enum definition order.
+ */
+ static final class SetsImmutableEnumSet5> {
+ @BeforeTemplate
+ @SuppressWarnings("SetsImmutableEnumSetIterable" /* This is a more specific template. */)
+ ImmutableSet before(T e1, T e2, T e3, T e4, T e5) {
+ return Refaster.anyOf(
+ ImmutableSet.of(e1, e2, e3, e4, e5), ImmutableSet.copyOf(EnumSet.of(e1, e2, e3, e4, e5)));
+ }
+
+ @AfterTemplate
+ @SuppressWarnings("unchecked")
+ ImmutableSet after(T e1, T e2, T e3, T e4, T e5) {
+ return Sets.immutableEnumSet(e1, e2, e3, e4, e5);
+ }
+ }
+
+ /**
+ * Prefer {@link Sets#immutableEnumSet(Enum, Enum[])} for enum collections to take advantage of
+ * the internally used {@link EnumSet}.
+ *
+ *
Warning: this rule is not completely behavior preserving: while the
+ * original code produces a set that iterates over its elements in the listed order, the
+ * replacement code iterates over the elements in enum definition order.
+ */
+ static final class SetsImmutableEnumSet6> {
+ @BeforeTemplate
+ ImmutableSet before(T e1, T e2, T e3, T e4, T e5, T e6) {
+ return ImmutableSet.of(e1, e2, e3, e4, e5, e6);
+ }
+
+ @AfterTemplate
+ @SuppressWarnings("unchecked")
+ ImmutableSet after(T e1, T e2, T e3, T e4, T e5, T e6) {
+ return Sets.immutableEnumSet(e1, e2, e3, e4, e5, e6);
+ }
+ }
+
+ /**
+ * Prefer {@link Sets#immutableEnumSet(Enum, Enum[])} for enum collections to take advantage of
+ * the internally used {@link EnumSet}.
+ */
+ static final class SetsImmutableEnumSetVarArgs> {
+ @BeforeTemplate
+ @SuppressWarnings("SetsImmutableEnumSetIterable" /* This is a more specific template. */)
+ ImmutableSet before(T e1, @Repeated T elements) {
+ return ImmutableSet.copyOf(EnumSet.of(e1, Refaster.asVarargs(elements)));
+ }
+
+ @AfterTemplate
+ ImmutableSet after(T e1, @Repeated T elements) {
+ return Sets.immutableEnumSet(e1, Refaster.asVarargs(elements));
+ }
+ }
+
+ /**
+ * Use {@link Sets#toImmutableEnumSet()} when possible, as it is more efficient than {@link
+ * ImmutableSet#toImmutableSet()} and produces a more compact object.
+ *
+ *
Warning: this rule is not completely behavior preserving: while the
+ * original code produces a set that iterates over its elements in encounter order, the
+ * replacement code iterates over the elements in enum definition order.
+ */
+ static final class StreamToImmutableEnumSet> {
+ @BeforeTemplate
+ ImmutableSet before(Stream stream) {
+ return stream.collect(toImmutableSet());
+ }
+
+ @AfterTemplate
+ @UseImportPolicy(STATIC_IMPORT_ALWAYS)
+ ImmutableSet after(Stream stream) {
+ return stream.collect(toImmutableEnumSet());
+ }
+ }
+}
diff --git a/error-prone-contrib/src/test/java/tech/picnic/errorprone/refasterrules/RefasterRulesTest.java b/error-prone-contrib/src/test/java/tech/picnic/errorprone/refasterrules/RefasterRulesTest.java
index a7c35621a8..30839af965 100644
--- a/error-prone-contrib/src/test/java/tech/picnic/errorprone/refasterrules/RefasterRulesTest.java
+++ b/error-prone-contrib/src/test/java/tech/picnic/errorprone/refasterrules/RefasterRulesTest.java
@@ -43,6 +43,7 @@ final class RefasterRulesTest {
EqualityRules.class,
FileRules.class,
InputStreamRules.class,
+ ImmutableEnumSetRules.class,
ImmutableListRules.class,
ImmutableListMultimapRules.class,
ImmutableMapRules.class,
diff --git a/error-prone-contrib/src/test/resources/tech/picnic/errorprone/refasterrules/AssortedRulesTestInput.java b/error-prone-contrib/src/test/resources/tech/picnic/errorprone/refasterrules/AssortedRulesTestInput.java
index 1f785293b0..98174797e0 100644
--- a/error-prone-contrib/src/test/resources/tech/picnic/errorprone/refasterrules/AssortedRulesTestInput.java
+++ b/error-prone-contrib/src/test/resources/tech/picnic/errorprone/refasterrules/AssortedRulesTestInput.java
@@ -1,10 +1,7 @@
package tech.picnic.errorprone.refasterrules;
-import static com.google.common.collect.ImmutableSet.toImmutableSet;
-
import com.google.common.base.Preconditions;
import com.google.common.base.Splitter;
-import com.google.common.collect.BoundType;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
@@ -24,8 +21,7 @@ public ImmutableSet