From 3d9aab7c5b9776929da49b32d41cdd9400dd1df1 Mon Sep 17 00:00:00 2001 From: Mohamed Sameh <110535847+mohamedsamehsalah@users.noreply.github.com> Date: Sun, 11 Aug 2024 15:01:53 +0200 Subject: [PATCH] Introduce `Class{Literal,Reference}Cast` Refaster rules (#1269) --- .../errorprone/refasterrules/ClassRules.java | 49 ++++++++++++++++++- .../refasterrules/ClassRulesTestInput.java | 18 +++++-- .../refasterrules/ClassRulesTestOutput.java | 18 +++++-- 3 files changed, 73 insertions(+), 12 deletions(-) diff --git a/error-prone-contrib/src/main/java/tech/picnic/errorprone/refasterrules/ClassRules.java b/error-prone-contrib/src/main/java/tech/picnic/errorprone/refasterrules/ClassRules.java index 2890dd1b9f..496b1f1fcb 100644 --- a/error-prone-contrib/src/main/java/tech/picnic/errorprone/refasterrules/ClassRules.java +++ b/error-prone-contrib/src/main/java/tech/picnic/errorprone/refasterrules/ClassRules.java @@ -3,6 +3,7 @@ import com.google.errorprone.refaster.Refaster; import com.google.errorprone.refaster.annotation.AfterTemplate; import com.google.errorprone.refaster.annotation.BeforeTemplate; +import java.util.function.Function; import java.util.function.Predicate; import tech.picnic.errorprone.refaster.annotation.OnlineDocumentation; @@ -37,7 +38,12 @@ boolean after(S object) { } } - /** Prefer {@link Class#isInstance(Object)} method references over more verbose alternatives. */ + /** + * Prefer {@link Class#isInstance(Object)} method references over lambda expressions that require + * naming a variable. + */ + // XXX: Once the `ClassReferenceIsInstancePredicate` rule is dropped, rename this rule to just + // `ClassIsInstancePredicate`. static final class ClassLiteralIsInstancePredicate { @BeforeTemplate Predicate before() { @@ -50,7 +56,11 @@ Predicate after() { } } - /** Prefer {@link Class#isInstance(Object)} method references over more verbose alternatives. */ + /** + * Prefer {@link Class#isInstance(Object)} method references over lambda expressions that require + * naming a variable. + */ + // XXX: Drop this rule once the `MethodReferenceUsage` rule is enabled by default. static final class ClassReferenceIsInstancePredicate { @BeforeTemplate Predicate before(Class clazz) { @@ -62,4 +72,39 @@ Predicate after(Class clazz) { return clazz::isInstance; } } + + /** + * Prefer {@link Class#cast(Object)} method references over lambda expressions that require naming + * a variable. + */ + // XXX: Once the `ClassReferenceCast` rule is dropped, rename this rule to just `ClassCast`. + static final class ClassLiteralCast { + @BeforeTemplate + @SuppressWarnings("unchecked") + Function before() { + return t -> (S) t; + } + + @AfterTemplate + Function after() { + return Refaster.clazz()::cast; + } + } + + /** + * Prefer {@link Class#cast(Object)} method references over lambda expressions that require naming + * a variable. + */ + // XXX: Drop this rule once the `MethodReferenceUsage` rule is enabled by default. + static final class ClassReferenceCast { + @BeforeTemplate + Function before(Class clazz) { + return o -> clazz.cast(o); + } + + @AfterTemplate + Function after(Class clazz) { + return clazz::cast; + } + } } diff --git a/error-prone-contrib/src/test/resources/tech/picnic/errorprone/refasterrules/ClassRulesTestInput.java b/error-prone-contrib/src/test/resources/tech/picnic/errorprone/refasterrules/ClassRulesTestInput.java index 2e94c24213..94f6db36f9 100644 --- a/error-prone-contrib/src/test/resources/tech/picnic/errorprone/refasterrules/ClassRulesTestInput.java +++ b/error-prone-contrib/src/test/resources/tech/picnic/errorprone/refasterrules/ClassRulesTestInput.java @@ -1,26 +1,34 @@ package tech.picnic.errorprone.refasterrules; import com.google.common.collect.ImmutableSet; -import java.io.IOException; +import java.util.function.Function; import java.util.function.Predicate; import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase; final class ClassRulesTest implements RefasterRuleCollectionTestCase { - boolean testClassIsInstance() throws IOException { + boolean testClassIsInstance() { return CharSequence.class.isAssignableFrom("foo".getClass()); } - ImmutableSet testInstanceof() throws IOException { + ImmutableSet testInstanceof() { Class clazz = CharSequence.class; return ImmutableSet.of(CharSequence.class.isInstance("foo"), clazz.isInstance("bar")); } - Predicate testClassLiteralIsInstancePredicate() throws IOException { + Predicate testClassLiteralIsInstancePredicate() { return s -> s instanceof CharSequence; } - Predicate testClassReferenceIsInstancePredicate() throws IOException { + Predicate testClassReferenceIsInstancePredicate() { Class clazz = CharSequence.class; return s -> clazz.isInstance(s); } + + Function testClassLiteralCast() { + return i -> (Integer) i; + } + + Function testClassReferenceCast() { + return i -> Integer.class.cast(i); + } } diff --git a/error-prone-contrib/src/test/resources/tech/picnic/errorprone/refasterrules/ClassRulesTestOutput.java b/error-prone-contrib/src/test/resources/tech/picnic/errorprone/refasterrules/ClassRulesTestOutput.java index 39c08a5068..2c4314157a 100644 --- a/error-prone-contrib/src/test/resources/tech/picnic/errorprone/refasterrules/ClassRulesTestOutput.java +++ b/error-prone-contrib/src/test/resources/tech/picnic/errorprone/refasterrules/ClassRulesTestOutput.java @@ -1,26 +1,34 @@ package tech.picnic.errorprone.refasterrules; import com.google.common.collect.ImmutableSet; -import java.io.IOException; +import java.util.function.Function; import java.util.function.Predicate; import tech.picnic.errorprone.refaster.test.RefasterRuleCollectionTestCase; final class ClassRulesTest implements RefasterRuleCollectionTestCase { - boolean testClassIsInstance() throws IOException { + boolean testClassIsInstance() { return CharSequence.class.isInstance("foo"); } - ImmutableSet testInstanceof() throws IOException { + ImmutableSet testInstanceof() { Class clazz = CharSequence.class; return ImmutableSet.of("foo" instanceof CharSequence, clazz.isInstance("bar")); } - Predicate testClassLiteralIsInstancePredicate() throws IOException { + Predicate testClassLiteralIsInstancePredicate() { return CharSequence.class::isInstance; } - Predicate testClassReferenceIsInstancePredicate() throws IOException { + Predicate testClassReferenceIsInstancePredicate() { Class clazz = CharSequence.class; return clazz::isInstance; } + + Function testClassLiteralCast() { + return Integer.class::cast; + } + + Function testClassReferenceCast() { + return Integer.class::cast; + } }