diff --git a/error-prone-contrib/src/main/java/tech/picnic/errorprone/refasterrules/MultimapRules.java b/error-prone-contrib/src/main/java/tech/picnic/errorprone/refasterrules/MultimapRules.java index c20184f17b..ca965013e0 100644 --- a/error-prone-contrib/src/main/java/tech/picnic/errorprone/refasterrules/MultimapRules.java +++ b/error-prone-contrib/src/main/java/tech/picnic/errorprone/refasterrules/MultimapRules.java @@ -6,7 +6,9 @@ import com.google.errorprone.refaster.annotation.AfterTemplate; import com.google.errorprone.refaster.annotation.BeforeTemplate; import java.util.Collection; +import java.util.Map; import java.util.Set; +import java.util.stream.Stream; import org.jspecify.annotations.Nullable; import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation; @@ -28,6 +30,21 @@ Set after(Multimap multimap) { } } + /** Prefer {@link Multimap#isEmpty()} over more contrived alternatives. */ + static final class MultimapIsEmpty { + @BeforeTemplate + boolean before(Multimap multimap) { + return Refaster.anyOf( + multimap.keySet(), multimap.keys(), multimap.values(), multimap.entries()) + .isEmpty(); + } + + @AfterTemplate + boolean after(Multimap multimap) { + return multimap.isEmpty(); + } + } + /** Prefer {@link Multimap#size()} over more contrived alternatives. */ static final class MultimapSize { @BeforeTemplate @@ -41,6 +58,32 @@ int after(Multimap multimap) { } } + /** Prefer {@link Multimap#containsKey(Object)} over more contrived alternatives. */ + static final class MultimapContainsKey { + @BeforeTemplate + boolean before(Multimap multimap, T key) { + return Refaster.anyOf(multimap.keySet(), multimap.keys()).contains(key); + } + + @AfterTemplate + boolean after(Multimap multimap, T key) { + return multimap.containsKey(key); + } + } + + /** Prefer {@link Multimap#containsValue(Object)} over more contrived alternatives. */ + static final class MultimapContainsValue { + @BeforeTemplate + boolean before(Multimap multimap, T value) { + return multimap.values().contains(value); + } + + @AfterTemplate + boolean after(Multimap multimap, T value) { + return multimap.containsValue(value); + } + } + /** * Prefer {@link Multimap#get(Object)} over more contrived alternatives. * @@ -59,4 +102,30 @@ Collection after(Multimap multimap, K key) { return multimap.get(key); } } + + /** Don't unnecessarily use {@link Multimap#entries()}. */ + static final class MultimapKeysStream { + @BeforeTemplate + Stream before(Multimap multimap) { + return multimap.entries().stream().map(Map.Entry::getKey); + } + + @AfterTemplate + Stream after(Multimap multimap) { + return multimap.keys().stream(); + } + } + + /** Don't unnecessarily use {@link Multimap#entries()}. */ + static final class MultimapValuesStream { + @BeforeTemplate + Stream before(Multimap multimap) { + return multimap.entries().stream().map(Map.Entry::getValue); + } + + @AfterTemplate + Stream after(Multimap multimap) { + return multimap.values().stream(); + } + } } diff --git a/error-prone-contrib/src/test/resources/tech/picnic/errorprone/refasterrules/MultimapRulesTestInput.java b/error-prone-contrib/src/test/resources/tech/picnic/errorprone/refasterrules/MultimapRulesTestInput.java index 97efdc53dd..e0c59ac6fa 100644 --- a/error-prone-contrib/src/test/resources/tech/picnic/errorprone/refasterrules/MultimapRulesTestInput.java +++ b/error-prone-contrib/src/test/resources/tech/picnic/errorprone/refasterrules/MultimapRulesTestInput.java @@ -5,26 +5,54 @@ import com.google.common.collect.Multimap; import com.google.common.collect.Multimaps; import java.util.Collection; +import java.util.Map; import java.util.Set; +import java.util.stream.Stream; import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase; final class MultimapRulesTest implements RefasterRuleCollectionTestCase { @Override public ImmutableSet elidedTypesAndStaticImports() { - return ImmutableSet.of(Multimaps.class); + return ImmutableSet.of(Map.class, Multimaps.class); } Set testMultimapKeySet() { return ImmutableSetMultimap.of("foo", "bar").asMap().keySet(); } + ImmutableSet testMultimapIsEmpty() { + return ImmutableSet.of( + ImmutableSetMultimap.of("foo", 1).keySet().isEmpty(), + ImmutableSetMultimap.of("bar", 2).keys().isEmpty(), + ImmutableSetMultimap.of("baz", 3).values().isEmpty(), + ImmutableSetMultimap.of("qux", 54).entries().isEmpty()); + } + int testMultimapSize() { return ImmutableSetMultimap.of().values().size(); } + ImmutableSet testMultimapContainsKey() { + return ImmutableSet.of( + ImmutableSetMultimap.of("foo", 1).keySet().contains("bar"), + ImmutableSetMultimap.of("baz", 1).keys().contains("qux")); + } + + boolean testMultimapContainsValue() { + return ImmutableSetMultimap.of("foo", 1).values().contains(2); + } + ImmutableSet> testMultimapGet() { return ImmutableSet.of( ImmutableSetMultimap.of(1, 2).asMap().get(1), Multimaps.asMap((Multimap) ImmutableSetMultimap.of(1, 2)).get(1)); } + + Stream testMultimapKeysStream() { + return ImmutableSetMultimap.of("foo", 1).entries().stream().map(Map.Entry::getKey); + } + + Stream testMultimapValuesStream() { + return ImmutableSetMultimap.of("foo", 1).entries().stream().map(Map.Entry::getValue); + } } diff --git a/error-prone-contrib/src/test/resources/tech/picnic/errorprone/refasterrules/MultimapRulesTestOutput.java b/error-prone-contrib/src/test/resources/tech/picnic/errorprone/refasterrules/MultimapRulesTestOutput.java index 51b74d661d..a9ab378d7c 100644 --- a/error-prone-contrib/src/test/resources/tech/picnic/errorprone/refasterrules/MultimapRulesTestOutput.java +++ b/error-prone-contrib/src/test/resources/tech/picnic/errorprone/refasterrules/MultimapRulesTestOutput.java @@ -5,26 +5,54 @@ import com.google.common.collect.Multimap; import com.google.common.collect.Multimaps; import java.util.Collection; +import java.util.Map; import java.util.Set; +import java.util.stream.Stream; import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase; final class MultimapRulesTest implements RefasterRuleCollectionTestCase { @Override public ImmutableSet elidedTypesAndStaticImports() { - return ImmutableSet.of(Multimaps.class); + return ImmutableSet.of(Map.class, Multimaps.class); } Set testMultimapKeySet() { return ImmutableSetMultimap.of("foo", "bar").keySet(); } + ImmutableSet testMultimapIsEmpty() { + return ImmutableSet.of( + ImmutableSetMultimap.of("foo", 1).isEmpty(), + ImmutableSetMultimap.of("bar", 2).isEmpty(), + ImmutableSetMultimap.of("baz", 3).isEmpty(), + ImmutableSetMultimap.of("qux", 54).isEmpty()); + } + int testMultimapSize() { return ImmutableSetMultimap.of().size(); } + ImmutableSet testMultimapContainsKey() { + return ImmutableSet.of( + ImmutableSetMultimap.of("foo", 1).containsKey("bar"), + ImmutableSetMultimap.of("baz", 1).containsKey("qux")); + } + + boolean testMultimapContainsValue() { + return ImmutableSetMultimap.of("foo", 1).containsValue(2); + } + ImmutableSet> testMultimapGet() { return ImmutableSet.of( ImmutableSetMultimap.of(1, 2).get(1), ((Multimap) ImmutableSetMultimap.of(1, 2)).get(1)); } + + Stream testMultimapKeysStream() { + return ImmutableSetMultimap.of("foo", 1).keys().stream(); + } + + Stream testMultimapValuesStream() { + return ImmutableSetMultimap.of("foo", 1).values().stream(); + } }