diff --git a/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/ExplicitArgumentEnumeration.java b/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/ExplicitArgumentEnumeration.java index 7770efe93c..8deed25125 100644 --- a/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/ExplicitArgumentEnumeration.java +++ b/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/ExplicitArgumentEnumeration.java @@ -113,7 +113,7 @@ public final class ExplicitArgumentEnumeration extends BugChecker .put(OBJECT_ENUMERABLE_ASSERT, "doesNotContainAnyElementsOf", "doesNotContain") .put(OBJECT_ENUMERABLE_ASSERT, "hasSameElementsAs", "containsOnly") .put(STEP_VERIFIER_STEP, "expectNextSequence", "expectNext") - .build(); + .buildOrThrow(); /** Instantiates a new {@link ExplicitArgumentEnumeration} instance. */ public ExplicitArgumentEnumeration() {} diff --git a/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/NonStaticImport.java b/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/NonStaticImport.java index eba7253b54..aca3b6af0c 100644 --- a/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/NonStaticImport.java +++ b/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/NonStaticImport.java @@ -182,7 +182,7 @@ private static ImmutableTable getUndesire } } - return imports.build(); + return imports.buildOrThrow(); } private static boolean shouldNotBeStaticallyImported(String type, String member) { diff --git a/error-prone-contrib/src/main/java/tech/picnic/errorprone/refasterrules/ImmutableTableRules.java b/error-prone-contrib/src/main/java/tech/picnic/errorprone/refasterrules/ImmutableTableRules.java new file mode 100644 index 0000000000..910fd5651a --- /dev/null +++ b/error-prone-contrib/src/main/java/tech/picnic/errorprone/refasterrules/ImmutableTableRules.java @@ -0,0 +1,114 @@ +package tech.picnic.errorprone.refasterrules; + +import static com.google.common.collect.ImmutableTable.toImmutableTable; +import static com.google.errorprone.refaster.ImportPolicy.STATIC_IMPORT_ALWAYS; + +import com.google.common.collect.ImmutableTable; +import com.google.common.collect.Table; +import com.google.common.collect.Tables; +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.MayOptionallyUse; +import com.google.errorprone.refaster.annotation.Placeholder; +import com.google.errorprone.refaster.annotation.UseImportPolicy; +import java.util.stream.Stream; +import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation; + +/** Refaster rules related to expressions dealing with {@link ImmutableTable}s. */ +@OnlineDocumentation +final class ImmutableTableRules { + private ImmutableTableRules() {} + + /** Prefer {@link ImmutableTable#builder()} over the associated constructor. */ + // XXX: This rule may drop generic type information, leading to non-compilable code. + static final class ImmutableTableBuilder { + @BeforeTemplate + ImmutableTable.Builder before() { + return new ImmutableTable.Builder<>(); + } + + @AfterTemplate + ImmutableTable.Builder after() { + return ImmutableTable.builder(); + } + } + + /** + * Prefer {@link ImmutableTable.Builder#buildOrThrow()} over the less explicit {@link + * ImmutableTable.Builder#build()}. + */ + static final class ImmutableTableBuilderBuildOrThrow { + @BeforeTemplate + ImmutableTable before(ImmutableTable.Builder builder) { + return builder.build(); + } + + @AfterTemplate + ImmutableTable after(ImmutableTable.Builder builder) { + return builder.buildOrThrow(); + } + } + + /** Prefer {@link ImmutableTable#of(Object, Object, Object)} over more contrived alternatives. */ + static final class CellToImmutableTable { + @BeforeTemplate + ImmutableTable before(Table.Cell cell) { + return Refaster.anyOf( + ImmutableTable.builder().put(cell).buildOrThrow(), + Stream.of(cell) + .collect( + toImmutableTable( + Table.Cell::getRowKey, Table.Cell::getColumnKey, Table.Cell::getValue))); + } + + @AfterTemplate + ImmutableTable after(Table.Cell cell) { + return ImmutableTable.of(cell.getRowKey(), cell.getColumnKey(), cell.getValue()); + } + } + + /** + * Don't map a stream's elements to table cells, only to subsequently collect them into an {@link + * ImmutableTable}. The collection can be performed directly. + */ + abstract static class StreamOfCellsToImmutableTable { + @Placeholder(allowsIdentity = true) + abstract R rowFunction(@MayOptionallyUse E element); + + @Placeholder(allowsIdentity = true) + abstract C columnFunction(@MayOptionallyUse E element); + + @Placeholder(allowsIdentity = true) + abstract V valueFunction(@MayOptionallyUse E element); + + @BeforeTemplate + ImmutableTable before(Stream stream) { + return stream + .map(e -> Tables.immutableCell(rowFunction(e), columnFunction(e), valueFunction(e))) + .collect( + toImmutableTable( + Table.Cell::getRowKey, Table.Cell::getColumnKey, Table.Cell::getValue)); + } + + @AfterTemplate + @UseImportPolicy(STATIC_IMPORT_ALWAYS) + ImmutableTable after(Stream stream) { + return stream.collect( + toImmutableTable(e -> rowFunction(e), e -> columnFunction(e), e -> valueFunction(e))); + } + } + + /** Prefer {@link ImmutableTable#of()} over more contrived alternatives . */ + static final class ImmutableTableOf { + @BeforeTemplate + ImmutableTable before() { + return ImmutableTable.builder().buildOrThrow(); + } + + @AfterTemplate + ImmutableTable after() { + return ImmutableTable.of(); + } + } +} 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 3f9250eb13..d7b47d307b 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 @@ -54,6 +54,7 @@ final class RefasterRulesTest { ImmutableSortedMapRules.class, ImmutableSortedMultisetRules.class, ImmutableSortedSetRules.class, + ImmutableTableRules.class, IntStreamRules.class, JUnitRules.class, JUnitToAssertJRules.class, diff --git a/error-prone-contrib/src/test/resources/tech/picnic/errorprone/refasterrules/ImmutableTableRulesTestInput.java b/error-prone-contrib/src/test/resources/tech/picnic/errorprone/refasterrules/ImmutableTableRulesTestInput.java new file mode 100644 index 0000000000..74707c4bc4 --- /dev/null +++ b/error-prone-contrib/src/test/resources/tech/picnic/errorprone/refasterrules/ImmutableTableRulesTestInput.java @@ -0,0 +1,48 @@ +package tech.picnic.errorprone.refasterrules; + +import static com.google.common.collect.ImmutableTable.toImmutableTable; + +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.ImmutableTable; +import com.google.common.collect.Table; +import com.google.common.collect.Tables; +import java.util.stream.Stream; +import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase; + +final class ImmutableTableRulesTest implements RefasterRuleCollectionTestCase { + @Override + public ImmutableSet elidedTypesAndStaticImports() { + return ImmutableSet.of(Table.class); + } + + ImmutableTable.Builder testImmutableTableBuilder() { + return new ImmutableTable.Builder<>(); + } + + ImmutableTable testImmutableTableBuilderBuildOrThrow() { + return ImmutableTable.builder().build(); + } + + ImmutableSet> testCellToImmutableTable() { + return ImmutableSet.of( + ImmutableTable.builder() + .put(Tables.immutableCell("foo", 1, "bar")) + .buildOrThrow(), + Stream.of(Tables.immutableCell("baz", 2, "qux")) + .collect( + toImmutableTable( + Table.Cell::getRowKey, Table.Cell::getColumnKey, Table.Cell::getValue))); + } + + ImmutableTable testStreamOfCellsToImmutableTable() { + return Stream.of(1, 2, 3) + .map(n -> Tables.immutableCell(n, n.toString(), n * 2)) + .collect( + toImmutableTable( + Table.Cell::getRowKey, Table.Cell::getColumnKey, Table.Cell::getValue)); + } + + ImmutableTable testImmutableTableOf() { + return ImmutableTable.builder().buildOrThrow(); + } +} diff --git a/error-prone-contrib/src/test/resources/tech/picnic/errorprone/refasterrules/ImmutableTableRulesTestOutput.java b/error-prone-contrib/src/test/resources/tech/picnic/errorprone/refasterrules/ImmutableTableRulesTestOutput.java new file mode 100644 index 0000000000..8b801bfec5 --- /dev/null +++ b/error-prone-contrib/src/test/resources/tech/picnic/errorprone/refasterrules/ImmutableTableRulesTestOutput.java @@ -0,0 +1,45 @@ +package tech.picnic.errorprone.refasterrules; + +import static com.google.common.collect.ImmutableTable.toImmutableTable; + +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.ImmutableTable; +import com.google.common.collect.Table; +import com.google.common.collect.Tables; +import java.util.stream.Stream; +import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase; + +final class ImmutableTableRulesTest implements RefasterRuleCollectionTestCase { + @Override + public ImmutableSet elidedTypesAndStaticImports() { + return ImmutableSet.of(Table.class); + } + + ImmutableTable.Builder testImmutableTableBuilder() { + return ImmutableTable.builder(); + } + + ImmutableTable testImmutableTableBuilderBuildOrThrow() { + return ImmutableTable.builder().buildOrThrow(); + } + + ImmutableSet> testCellToImmutableTable() { + return ImmutableSet.of( + ImmutableTable.of( + Tables.immutableCell("foo", 1, "bar").getRowKey(), + Tables.immutableCell("foo", 1, "bar").getColumnKey(), + Tables.immutableCell("foo", 1, "bar").getValue()), + ImmutableTable.of( + Tables.immutableCell("baz", 2, "qux").getRowKey(), + Tables.immutableCell("baz", 2, "qux").getColumnKey(), + Tables.immutableCell("baz", 2, "qux").getValue())); + } + + ImmutableTable testStreamOfCellsToImmutableTable() { + return Stream.of(1, 2, 3).collect(toImmutableTable(n -> n, n -> n.toString(), n -> n * 2)); + } + + ImmutableTable testImmutableTableOf() { + return ImmutableTable.of(); + } +}