From 580ef407bbb1459ba52f19b4d8e865c688af20ab Mon Sep 17 00:00:00 2001 From: Stephan Schroevers Date: Sun, 29 Dec 2024 20:15:41 +0100 Subject: [PATCH] Introduce `ImmutableTableRules` Refaster rule collection --- .../refasterrules/ImmutableTableRules.java | 114 ++++++++++++++++++ .../refasterrules/RefasterRulesTest.java | 1 + .../ImmutableTableRulesTestInput.java | 48 ++++++++ .../ImmutableTableRulesTestOutput.java | 45 +++++++ 4 files changed, 208 insertions(+) create mode 100644 error-prone-contrib/src/main/java/tech/picnic/errorprone/refasterrules/ImmutableTableRules.java create mode 100644 error-prone-contrib/src/test/resources/tech/picnic/errorprone/refasterrules/ImmutableTableRulesTestInput.java create mode 100644 error-prone-contrib/src/test/resources/tech/picnic/errorprone/refasterrules/ImmutableTableRulesTestOutput.java 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(); + } +}