From 6e867b5bbdaa76dcd767d06bf445d391528b5b1a Mon Sep 17 00:00:00 2001 From: Michail Plushnikov Date: Sun, 17 Sep 2023 22:59:40 +0200 Subject: [PATCH] [lombok] IDEA-308468 fix handling of @EqualsAndHashCode.Exclude for @Value and @Data classes GitOrigin-RevId: 54fb1f344b4d581ca2308181acdeb99f35ead09f --- .../clazz/EqualsAndHashCodeProcessor.java | 26 +++++++---- .../processor/clazz/ToStringProcessor.java | 13 +++--- .../EqualsAndHashCodeToStringHandler.java | 8 ++-- .../delombok/DelombokDataActionTest.java | 4 +- .../delombok/DelombokValueActionTest.java | 3 ++ .../data/afterDataWithEAHCExclude.java | 43 ++++++++++++++++++ .../data/beforeDataWithEAHCExclude.java | 10 +++++ .../value/afterValueWithEAHCExclude.java | 45 +++++++++++++++++++ .../value/beforeValueWithEAHCExclude.java | 10 +++++ 9 files changed, 142 insertions(+), 20 deletions(-) create mode 100644 plugins/lombok/testData/action/delombok/data/afterDataWithEAHCExclude.java create mode 100644 plugins/lombok/testData/action/delombok/data/beforeDataWithEAHCExclude.java create mode 100644 plugins/lombok/testData/action/delombok/value/afterValueWithEAHCExclude.java create mode 100644 plugins/lombok/testData/action/delombok/value/beforeValueWithEAHCExclude.java diff --git a/plugins/lombok/src/main/java/de/plushnikov/intellij/plugin/processor/clazz/EqualsAndHashCodeProcessor.java b/plugins/lombok/src/main/java/de/plushnikov/intellij/plugin/processor/clazz/EqualsAndHashCodeProcessor.java index af5c6bf701c4..a84efc361f3e 100644 --- a/plugins/lombok/src/main/java/de/plushnikov/intellij/plugin/processor/clazz/EqualsAndHashCodeProcessor.java +++ b/plugins/lombok/src/main/java/de/plushnikov/intellij/plugin/processor/clazz/EqualsAndHashCodeProcessor.java @@ -26,6 +26,9 @@ import java.util.Collections; import java.util.List; import java.util.function.Supplier; +import static de.plushnikov.intellij.plugin.LombokClassNames.EQUALS_AND_HASHCODE_EXCLUDE; +import static de.plushnikov.intellij.plugin.LombokClassNames.EQUALS_AND_HASHCODE_INCLUDE; + /** * Inspect and validate @EqualsAndHashCode lombok annotation on a class * Creates equals/hashcode method for fields of this class @@ -38,8 +41,6 @@ public final class EqualsAndHashCodeProcessor extends AbstractClassProcessor { private static final String CAN_EQUAL_METHOD_NAME = "canEqual"; private static final String INCLUDE_ANNOTATION_METHOD = "replaces"; - private static final String EQUALSANDHASHCODE_INCLUDE = LombokClassNames.EQUALS_AND_HASHCODE_INCLUDE; - private static final String EQUALSANDHASHCODE_EXCLUDE = LombokClassNames.EQUALS_AND_HASHCODE_EXCLUDE; EqualsAndHashCodeProcessor() { super(PsiMethod.class, LombokClassNames.EQUALS_AND_HASHCODE); @@ -197,7 +198,10 @@ public final class EqualsAndHashCodeProcessor extends AbstractClassProcessor { PsiClass containingClass = m.getContainingClass(); PsiAnnotation anno = (PsiAnnotation)m.getNavigationElement(); return createEqualsBlockString(containingClass, anno, hasCanEqualMethod, - EqualsAndHashCodeToStringHandler.filterMembers(containingClass, anno, true, INCLUDE_ANNOTATION_METHOD, null)); + EqualsAndHashCodeToStringHandler.filterMembers(containingClass, anno, true, + INCLUDE_ANNOTATION_METHOD, null, + EQUALS_AND_HASHCODE_INCLUDE, + EQUALS_AND_HASHCODE_EXCLUDE)); }); return methodBuilder; } @@ -215,8 +219,10 @@ public final class EqualsAndHashCodeProcessor extends AbstractClassProcessor { PsiClass containingClass = m.getContainingClass(); PsiAnnotation anno = (PsiAnnotation)m.getNavigationElement(); return createHashcodeBlockString(containingClass, anno, - EqualsAndHashCodeToStringHandler.filterMembers(containingClass, anno, true, INCLUDE_ANNOTATION_METHOD, - null)); + EqualsAndHashCodeToStringHandler.filterMembers(containingClass, anno, true, + INCLUDE_ANNOTATION_METHOD, null, + EQUALS_AND_HASHCODE_INCLUDE, + EQUALS_AND_HASHCODE_EXCLUDE)); }); } @@ -243,8 +249,8 @@ public final class EqualsAndHashCodeProcessor extends AbstractClassProcessor { } private static void copyOnXAnnotationsForFirstParam(@NotNull PsiAnnotation psiAnnotation, @NotNull LombokLightParameter lightParameter) { - PsiModifierList methodParameterModifierList = lightParameter.getModifierList(); - LombokCopyableAnnotations.copyOnXAnnotations(psiAnnotation, methodParameterModifierList, "onParam"); + PsiModifierList methodParameterModifierList = lightParameter.getModifierList(); + LombokCopyableAnnotations.copyOnXAnnotations(psiAnnotation, methodParameterModifierList, "onParam"); } private @NotNull String createEqualsBlockString(@NotNull PsiClass psiClass, @@ -387,7 +393,7 @@ public final class EqualsAndHashCodeProcessor extends AbstractClassProcessor { @Override public Collection collectProcessedAnnotations(@NotNull PsiClass psiClass) { final Collection result = super.collectProcessedAnnotations(psiClass); - addFieldsAnnotation(result, psiClass, EQUALSANDHASHCODE_INCLUDE, EQUALSANDHASHCODE_EXCLUDE); + addFieldsAnnotation(result, psiClass, EQUALS_AND_HASHCODE_INCLUDE, EQUALS_AND_HASHCODE_EXCLUDE); return result; } @@ -396,7 +402,9 @@ public final class EqualsAndHashCodeProcessor extends AbstractClassProcessor { final PsiClass containingClass = psiField.getContainingClass(); if (null != containingClass) { final String psiFieldName = psiField.getName(); - if (EqualsAndHashCodeToStringHandler.filterMembers(containingClass, psiAnnotation, true, INCLUDE_ANNOTATION_METHOD, null).stream() + if (EqualsAndHashCodeToStringHandler.filterMembers(containingClass, psiAnnotation, true, + INCLUDE_ANNOTATION_METHOD, null, + EQUALS_AND_HASHCODE_INCLUDE, EQUALS_AND_HASHCODE_EXCLUDE).stream() .map(MemberInfo::getName).anyMatch(psiFieldName::equals)) { return LombokPsiElementUsage.READ; } diff --git a/plugins/lombok/src/main/java/de/plushnikov/intellij/plugin/processor/clazz/ToStringProcessor.java b/plugins/lombok/src/main/java/de/plushnikov/intellij/plugin/processor/clazz/ToStringProcessor.java index 1f27ce6c68de..6f47478e4a79 100644 --- a/plugins/lombok/src/main/java/de/plushnikov/intellij/plugin/processor/clazz/ToStringProcessor.java +++ b/plugins/lombok/src/main/java/de/plushnikov/intellij/plugin/processor/clazz/ToStringProcessor.java @@ -20,6 +20,9 @@ import java.util.Collection; import java.util.Collections; import java.util.List; +import static de.plushnikov.intellij.plugin.LombokClassNames.TO_STRING_EXCLUDE; +import static de.plushnikov.intellij.plugin.LombokClassNames.TO_STRING_INCLUDE; + /** * Inspect and validate @ToString lombok annotation on a class * Creates toString() method for fields of this class @@ -32,8 +35,6 @@ public final class ToStringProcessor extends AbstractClassProcessor { private static final String INCLUDE_ANNOTATION_METHOD = "name"; private static final String INCLUDE_ANNOTATION_RANK = "rank"; private static final String INCLUDE_ANNOTATION_SKIP_NULL = "skipNull"; - private static final String TOSTRING_INCLUDE = LombokClassNames.TO_STRING_INCLUDE; - private static final String TOSTRING_EXCLUDE = LombokClassNames.TO_STRING_EXCLUDE; public ToStringProcessor() { super(PsiMethod.class, LombokClassNames.TO_STRING); @@ -102,7 +103,8 @@ public final class ToStringProcessor extends AbstractClassProcessor { final Collection memberInfos = EqualsAndHashCodeToStringHandler.filterMembers(psiClass, psiAnnotation, false, INCLUDE_ANNOTATION_METHOD, - ConfigKey.TOSTRING_ONLY_EXPLICITLY_INCLUDED); + ConfigKey.TOSTRING_ONLY_EXPLICITLY_INCLUDED, + TO_STRING_INCLUDE, TO_STRING_EXCLUDE); final PsiMethod stringMethod = createToStringMethod(psiClass, memberInfos, psiAnnotation, false); return Collections.singletonList(stringMethod); } @@ -195,7 +197,7 @@ public final class ToStringProcessor extends AbstractClassProcessor { @Override public Collection collectProcessedAnnotations(@NotNull PsiClass psiClass) { final Collection result = super.collectProcessedAnnotations(psiClass); - addFieldsAnnotation(result, psiClass, TOSTRING_INCLUDE, TOSTRING_EXCLUDE); + addFieldsAnnotation(result, psiClass, TO_STRING_INCLUDE, TO_STRING_EXCLUDE); return result; } @@ -206,7 +208,8 @@ public final class ToStringProcessor extends AbstractClassProcessor { final String psiFieldName = psiField.getName(); final Collection memberInfos = EqualsAndHashCodeToStringHandler.filterMembers(containingClass, psiAnnotation, false, - INCLUDE_ANNOTATION_METHOD, ConfigKey.TOSTRING_ONLY_EXPLICITLY_INCLUDED); + INCLUDE_ANNOTATION_METHOD, ConfigKey.TOSTRING_ONLY_EXPLICITLY_INCLUDED, + TO_STRING_INCLUDE, TO_STRING_EXCLUDE); if (memberInfos.stream().filter(MemberInfo::isField).map(MemberInfo::getName).anyMatch(psiFieldName::equals)) { return LombokPsiElementUsage.READ; } diff --git a/plugins/lombok/src/main/java/de/plushnikov/intellij/plugin/processor/handler/EqualsAndHashCodeToStringHandler.java b/plugins/lombok/src/main/java/de/plushnikov/intellij/plugin/processor/handler/EqualsAndHashCodeToStringHandler.java index b6f04593b0c7..bbfc132a30a5 100644 --- a/plugins/lombok/src/main/java/de/plushnikov/intellij/plugin/processor/handler/EqualsAndHashCodeToStringHandler.java +++ b/plugins/lombok/src/main/java/de/plushnikov/intellij/plugin/processor/handler/EqualsAndHashCodeToStringHandler.java @@ -89,14 +89,12 @@ public final class EqualsAndHashCodeToStringHandler { public static Collection filterMembers(@NotNull PsiClass psiClass, @NotNull PsiAnnotation psiAnnotation, boolean filterTransient, String includeAnnotationProperty, - @Nullable ConfigKey onlyExplicitlyIncludedConfigKey) { + @Nullable ConfigKey onlyExplicitlyIncludedConfigKey, + @NotNull String annotationIncludeFQN, + @NotNull String annotationExcludeFQN) { final boolean explicitOf = PsiAnnotationUtil.hasDeclaredProperty(psiAnnotation, "of"); final boolean onlyExplicitlyIncluded = checkOnlyExplicitlyIncluded(psiClass, psiAnnotation, onlyExplicitlyIncludedConfigKey); - final String annotationFQN = psiAnnotation.getQualifiedName(); - final String annotationIncludeFQN = annotationFQN + ".Include"; - final String annotationExcludeFQN = annotationFQN + ".Exclude"; - //Having both exclude and of generates a warning; the exclude parameter will be ignored in that case. final Collection ofProperty; final Collection excludeProperty; diff --git a/plugins/lombok/src/test/java/de/plushnikov/intellij/plugin/action/delombok/DelombokDataActionTest.java b/plugins/lombok/src/test/java/de/plushnikov/intellij/plugin/action/delombok/DelombokDataActionTest.java index 1d19cef9af11..cc1742d42aa6 100644 --- a/plugins/lombok/src/test/java/de/plushnikov/intellij/plugin/action/delombok/DelombokDataActionTest.java +++ b/plugins/lombok/src/test/java/de/plushnikov/intellij/plugin/action/delombok/DelombokDataActionTest.java @@ -18,7 +18,9 @@ public class DelombokDataActionTest extends LombokLightActionTestCase { public void testDataSimple() throws Exception { doTest(); } - + public void testDataWithEAHCExclude() throws Exception { + doTest(); + } public void testDataWithAnnotations() throws Exception { doTest(); } diff --git a/plugins/lombok/src/test/java/de/plushnikov/intellij/plugin/action/delombok/DelombokValueActionTest.java b/plugins/lombok/src/test/java/de/plushnikov/intellij/plugin/action/delombok/DelombokValueActionTest.java index ad2183efd79d..224eeb0b14b2 100644 --- a/plugins/lombok/src/test/java/de/plushnikov/intellij/plugin/action/delombok/DelombokValueActionTest.java +++ b/plugins/lombok/src/test/java/de/plushnikov/intellij/plugin/action/delombok/DelombokValueActionTest.java @@ -18,6 +18,9 @@ public class DelombokValueActionTest extends LombokLightActionTestCase { public void testValuePlain() throws Exception { doTest(); } + public void testValueWithEAHCExclude() throws Exception { + doTest(); + } public void testValueNonFinalOnField() throws Exception { doTest(); diff --git a/plugins/lombok/testData/action/delombok/data/afterDataWithEAHCExclude.java b/plugins/lombok/testData/action/delombok/data/afterDataWithEAHCExclude.java new file mode 100644 index 000000000000..a37587fc7b6c --- /dev/null +++ b/plugins/lombok/testData/action/delombok/data/afterDataWithEAHCExclude.java @@ -0,0 +1,43 @@ +final class Class1 { + + + private final String f1; + + @lombok.EqualsAndHashCode.Exclude + private final String f2; + + public Class1(String f1, String f2) { + this.f1 = f1; + this.f2 = f2; + } + + public String getF1() { + return this.f1; + } + + public String getF2() { + return this.f2; + } + + public boolean equals(final Object o) { + if (o == this) return true; + if (!(o instanceof Class1)) return false; + final Class1 other = (Class1) o; + final Object this$f1 = this.getF1(); + final Object other$f1 = other.getF1(); + if (this$f1 == null ? other$f1 != null : !this$f1.equals(other$f1)) return false; + return true; + } + + public int hashCode() { + final int PRIME = 59; + int result = 1; + final Object $f1 = this.getF1(); + result = result * PRIME + ($f1 == null ? 43 : $f1.hashCode()); + return result; + } + + public String toString() { + return "Class1(f1=" + this.getF1() + ", f2=" + this.getF2() + ")"; + } +} \ No newline at end of file diff --git a/plugins/lombok/testData/action/delombok/data/beforeDataWithEAHCExclude.java b/plugins/lombok/testData/action/delombok/data/beforeDataWithEAHCExclude.java new file mode 100644 index 000000000000..9f001d0796a9 --- /dev/null +++ b/plugins/lombok/testData/action/delombok/data/beforeDataWithEAHCExclude.java @@ -0,0 +1,10 @@ +import lombok.Data; +@lombok.Data +final class Class1 { + + + private final String f1; + + @lombok.EqualsAndHashCode.Exclude + private final String f2; +} \ No newline at end of file diff --git a/plugins/lombok/testData/action/delombok/value/afterValueWithEAHCExclude.java b/plugins/lombok/testData/action/delombok/value/afterValueWithEAHCExclude.java new file mode 100644 index 000000000000..0dc3007e1646 --- /dev/null +++ b/plugins/lombok/testData/action/delombok/value/afterValueWithEAHCExclude.java @@ -0,0 +1,45 @@ +final +class Class1 { + + + private final String f1; + + @lombok.EqualsAndHashCode.Exclude + private final + String f2; + + public Class1(String f1, String f2) { + this.f1 = f1; + this.f2 = f2; + } + + public String getF1() { + return this.f1; + } + + public String getF2() { + return this.f2; + } + + public boolean equals(final Object o) { + if (o == this) return true; + if (!(o instanceof Class1)) return false; + final Class1 other = (Class1) o; + final Object this$f1 = this.getF1(); + final Object other$f1 = other.getF1(); + if (this$f1 == null ? other$f1 != null : !this$f1.equals(other$f1)) return false; + return true; + } + + public int hashCode() { + final int PRIME = 59; + int result = 1; + final Object $f1 = this.getF1(); + result = result * PRIME + ($f1 == null ? 43 : $f1.hashCode()); + return result; + } + + public String toString() { + return "Class1(f1=" + this.getF1() + ", f2=" + this.getF2() + ")"; + } +} \ No newline at end of file diff --git a/plugins/lombok/testData/action/delombok/value/beforeValueWithEAHCExclude.java b/plugins/lombok/testData/action/delombok/value/beforeValueWithEAHCExclude.java new file mode 100644 index 000000000000..e02b9f0b3e34 --- /dev/null +++ b/plugins/lombok/testData/action/delombok/value/beforeValueWithEAHCExclude.java @@ -0,0 +1,10 @@ +import lombok.Value; +@lombok.Value +class Class1 { + + + String f1; + + @lombok.EqualsAndHashCode.Exclude + String f2; +} \ No newline at end of file