[lombok] IDEA-308468 fix handling of @EqualsAndHashCode.Exclude for @Value and @Data classes

GitOrigin-RevId: 54fb1f344b4d581ca2308181acdeb99f35ead09f
This commit is contained in:
Michail Plushnikov
2023-09-17 22:41:16 +00:00
committed by intellij-monorepo-bot
parent fcb675c6a0
commit 6e867b5bbd
9 changed files with 142 additions and 20 deletions
@@ -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<PsiAnnotation> collectProcessedAnnotations(@NotNull PsiClass psiClass) {
final Collection<PsiAnnotation> 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;
}
@@ -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<MemberInfo> 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<PsiAnnotation> collectProcessedAnnotations(@NotNull PsiClass psiClass) {
final Collection<PsiAnnotation> 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<MemberInfo> 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;
}
@@ -89,14 +89,12 @@ public final class EqualsAndHashCodeToStringHandler {
public static Collection<MemberInfo> 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<String> ofProperty;
final Collection<String> excludeProperty;
@@ -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();
}
@@ -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();
@@ -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() + ")";
}
}
@@ -0,0 +1,10 @@
import lombok.Data;
@lombok.Data
final class Class1 {
<caret>
private final String f1;
@lombok.EqualsAndHashCode.Exclude
private final String f2;
}
@@ -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() + ")";
}
}
@@ -0,0 +1,10 @@
import lombok.Value;
@lombok.Value
class Class1 {
<caret>
String f1;
@lombok.EqualsAndHashCode.Exclude
String f2;
}