[lombok] IDEA-354696 Fixed @SuperBuilder: 'toBuilder()' is already defined, if method is already defined in class

GitOrigin-RevId: 4a30ac0f71361b6d3f18be2654579ba574bc791d
This commit is contained in:
Michail Plushnikov
2024-09-02 20:43:08 +02:00
committed by intellij-monorepo-bot
parent 54a9138d9b
commit f98149cc70
5 changed files with 166 additions and 8 deletions

View File

@@ -217,7 +217,7 @@ public class BuilderHandler {
public boolean validate(@NotNull PsiMethod psiMethod, @NotNull PsiAnnotation psiAnnotation, @NotNull ProblemSink problemSink) {
final PsiClass psiClass = psiMethod.getContainingClass();
boolean result = null!=psiClass && validateAnnotationOnRightType(psiClass, problemSink);
boolean result = null != psiClass && validateAnnotationOnRightType(psiClass, problemSink);
if (result) {
final String builderClassName = getBuilderClassName(psiClass, psiAnnotation, psiMethod);
@@ -383,7 +383,7 @@ public class BuilderHandler {
}
String relevantReturnType = psiClass.getName();
if(psiClass instanceof PsiAnonymousClass psiAnonymousClass) {
if (psiClass instanceof PsiAnonymousClass psiAnonymousClass) {
relevantReturnType = psiAnonymousClass.getBaseClassType().getClassName();
}
@@ -391,7 +391,8 @@ public class BuilderHandler {
final PsiType psiMethodReturnType = psiMethod.getReturnType();
if (psiMethodReturnType instanceof PsiClassType psiClassType) {
relevantReturnType = psiClassType.getClassName();
}else if (null != psiMethodReturnType) {
}
else if (null != psiMethodReturnType) {
relevantReturnType = PsiNameHelper.getShortClassName(psiMethodReturnType.getPresentableText());
}
}
@@ -406,7 +407,14 @@ public class BuilderHandler {
return replace(builderClassNamePattern, "*", capitalize(StringUtil.notNullize(returnTypeName)));
}
boolean hasMethod(@NotNull PsiClass psiClass, @NotNull String builderMethodName) {
static boolean hasMethod(@NotNull PsiClass psiClass, @NotNull String builderMethodName, int paramCount) {
final Collection<PsiMethod> existingMethods = PsiClassUtil.collectClassMethodsIntern(psiClass);
return existingMethods.stream()
.filter(method -> method.getParameterList().getParametersCount() == paramCount)
.map(PsiMethod::getName).anyMatch(builderMethodName::equals);
}
static boolean hasStaticMethod(@NotNull PsiClass psiClass, @NotNull String builderMethodName) {
final Collection<PsiMethod> existingMethods = PsiClassUtil.collectClassStaticMethodsIntern(psiClass);
return existingMethods.stream().map(PsiMethod::getName).anyMatch(builderMethodName::equals);
}
@@ -443,7 +451,7 @@ public class BuilderHandler {
@NotNull PsiClass builderPsiClass,
@NotNull PsiAnnotation psiAnnotation) {
final String builderMethodName = getBuilderMethodName(psiAnnotation);
if (!builderMethodName.isEmpty() && !hasMethod(containingClass, builderMethodName)) {
if (!builderMethodName.isEmpty() && !hasStaticMethod(containingClass, builderMethodName)) {
final PsiType psiTypeWithGenerics = PsiClassUtil.getTypeWithGenerics(builderPsiClass);
final String blockText = String.format("return new %s();", psiTypeWithGenerics.getCanonicalText(false));
@@ -559,7 +567,8 @@ public class BuilderHandler {
final PsiSubstitutor builderSubstitutor = getBuilderSubstitutor(psiClass, builderClass);
final String accessVisibility = getBuilderInnerAccessVisibility(psiAnnotation);
final String setterPrefix = getSetterPrefix(psiAnnotation);
final LombokNullAnnotationLibrary nullAnnotationLibrary = ConfigDiscovery.getInstance().getAddNullAnnotationLombokConfigProperty(psiClass);
final LombokNullAnnotationLibrary nullAnnotationLibrary =
ConfigDiscovery.getInstance().getAddNullAnnotationLombokConfigProperty(psiClass);
return createBuilderInfos(psiClass, psiClassMethod)
.map(info -> info.withSubstitutor(builderSubstitutor))

View File

@@ -145,7 +145,7 @@ public class SuperBuilderHandler extends BuilderHandler {
@NotNull PsiAnnotation psiAnnotation,
@NotNull PsiClassType psiTypeBaseWithGenerics) {
final String builderMethodName = getBuilderMethodName(psiAnnotation);
if (builderMethodName.isEmpty() || hasMethod(containingClass, builderMethodName)) {
if (builderMethodName.isEmpty() || hasStaticMethod(containingClass, builderMethodName)) {
return Optional.empty();
}
@@ -170,7 +170,7 @@ public class SuperBuilderHandler extends BuilderHandler {
@NotNull PsiClass builderImplClass,
@NotNull PsiAnnotation psiAnnotation,
@NotNull PsiClassType psiTypeBaseWithGenerics) {
if (!shouldGenerateToBuilderMethods(psiAnnotation)) {
if (!shouldGenerateToBuilderMethods(psiAnnotation) || hasMethod(containingClass, TO_BUILDER_METHOD_NAME, 0)) {
return Optional.empty();
}

View File

@@ -39,6 +39,10 @@ public class SuperBuilderTest extends AbstractLombokParsingTestCase {
doTest(true);
}
public void testSuperbuilder$SuperBuilderToBuilderOverride() {
doTest(true);
}
//TODO Implement AnnotatedTypes handling/delombok
// public void testSuperbuilder$SuperBuilderSingularAnnotatedTypes() {
// doTest(true);

View File

@@ -0,0 +1,121 @@
class Base {
private String string;
protected Base(BaseBuilder<?, ?> b) {
this.string = b.string;
}
public static BaseBuilder<?, ?> builder() {
return new Base.BaseBuilderImpl();
}
public String getString() {
return this.string;
}
public BaseBuilder<?, ?> toBuilder() {
return new Base.BaseBuilderImpl().$fillValuesFrom(this);
}
public static abstract class BaseBuilder<C extends Base, B extends BaseBuilder<C, B>> {
private String string;
private static void $fillValuesFromInstanceIntoBuilder(Base instance, BaseBuilder<?, ?> b) {
b.string(instance.string);
}
public B string(String string) {
this.string = string;
return self();
}
protected B $fillValuesFrom(C instance) {
Base.BaseBuilder.$fillValuesFromInstanceIntoBuilder(instance, this);
return self();
}
protected abstract B self();
public abstract C build();
public String toString() {
return "Base.BaseBuilder(string=" + this.string + ")";
}
}
private static final class BaseBuilderImpl extends BaseBuilder<Base, BaseBuilderImpl> {
private BaseBuilderImpl() {
}
protected BaseBuilderImpl self() {
return this;
}
public Base build() {
return new Base(this);
}
}
}
class Sub extends Base {
private int number;
protected Sub(SubBuilder<?, ?> builder) {
super(builder);
}
public static SubBuilder<?, ?> builder() {
return new Sub.SubBuilderImpl();
}
public SubBuilder<?, ?> toBuilder() {
// custom code should go here
return new SubBuilderImpl().$fillValuesFrom(this);
}
public int getNumber() {
return this.number;
}
public static abstract class SubBuilder<C extends Sub, B extends SubBuilder<C, B>> extends BaseBuilder<C, B> {
private int number;
private static void $fillValuesFromInstanceIntoBuilder(Sub instance, SubBuilder<?, ?> b) {
b.number(instance.number);
}
public B number(int number) {
this.number = number;
return self();
}
protected B $fillValuesFrom(C instance) {
super.$fillValuesFrom(instance);
Sub.SubBuilder.$fillValuesFromInstanceIntoBuilder(instance, this);
return self();
}
protected abstract B self();
public abstract C build();
public String toString() {
return "Sub.SubBuilder(super=" + super.toString() + ", number=" + this.number + ")";
}
}
private static final class SubBuilderImpl extends SubBuilder<Sub, SubBuilderImpl> {
private SubBuilderImpl() {
}
protected SubBuilderImpl self() {
return this;
}
public Sub build() {
return new Sub(this);
}
}
}

View File

@@ -0,0 +1,24 @@
import lombok.Getter;
import lombok.experimental.SuperBuilder;
@Getter
@SuperBuilder(toBuilder = true)
class Base {
private String string;
}
@Getter
@SuperBuilder(toBuilder = true)
class Sub extends Base {
private int number;
protected Sub(SubBuilder<?, ?> builder) {
super(builder);
}
public SubBuilder<?, ?> toBuilder() {
// custom code should go here
return new SubBuilderImpl().$fillValuesFrom(this);
}
}