From b36d9ecce5967ef3f778835a8bd4132addf4c6dd Mon Sep 17 00:00:00 2001 From: junkfactory <2998269+junkfactory@users.noreply.github.com> Date: Tue, 6 Aug 2024 23:27:13 -0700 Subject: [PATCH 1/2] Handle immutables in detecting addTo method --- .../generators/BuilderMethodsGenerator.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/main/java/com/github/junkfactory/innerbuilder/generators/BuilderMethodsGenerator.java b/src/main/java/com/github/junkfactory/innerbuilder/generators/BuilderMethodsGenerator.java index 17c6c6a..faec658 100644 --- a/src/main/java/com/github/junkfactory/innerbuilder/generators/BuilderMethodsGenerator.java +++ b/src/main/java/com/github/junkfactory/innerbuilder/generators/BuilderMethodsGenerator.java @@ -64,6 +64,9 @@ private PsiMethod generateFieldMethod(PsiField field) { } private PsiMethod findAddMethod(PsiField field) { + if (isFieldInitializedWithImmutableCollection(field)) { + return null; + } var fieldClass = PsiUtil.resolveClassInClassTypeOnly(field.getType()); var methods = Optional.ofNullable(fieldClass) .map(PsiClass::getAllMethods) @@ -76,6 +79,19 @@ private PsiMethod findAddMethod(PsiField field) { return null; } + private boolean isFieldInitializedWithImmutableCollection(PsiField field) { + var initializer = field.getInitializer(); + if (null == initializer) { + return false; + } + var initializerType = initializer.getType(); + if (null == initializerType) { + return false; + } + var initializerClass = PsiUtil.resolveClassInClassTypeOnly(initializerType); + return null != initializerClass && initializerClass.hasModifierProperty(PsiModifier.ABSTRACT); + } + private PsiMethod generateAddToCollection(PsiField field, PsiMethod fieldAddMethod) { //resolve the generic type of the collection via the parameter type of the add method var param = Objects.requireNonNull(fieldAddMethod.getParameterList().getParameter(0)); From 489f7e4a14b779543c9df586d3ea69f1a0b97253 Mon Sep 17 00:00:00 2001 From: junkfactory <2998269+junkfactory@users.noreply.github.com> Date: Tue, 6 Aug 2024 23:49:05 -0700 Subject: [PATCH 2/2] Add putTo map (or any class with a put(x,y) method --- .../generators/BuilderMethodsGenerator.java | 56 ++++++++---------- .../innerbuilder/generators/Utils.java | 59 +++++++++++++++++-- 2 files changed, 77 insertions(+), 38 deletions(-) diff --git a/src/main/java/com/github/junkfactory/innerbuilder/generators/BuilderMethodsGenerator.java b/src/main/java/com/github/junkfactory/innerbuilder/generators/BuilderMethodsGenerator.java index faec658..6cb4462 100644 --- a/src/main/java/com/github/junkfactory/innerbuilder/generators/BuilderMethodsGenerator.java +++ b/src/main/java/com/github/junkfactory/innerbuilder/generators/BuilderMethodsGenerator.java @@ -2,7 +2,6 @@ import com.github.junkfactory.innerbuilder.ui.JavaInnerBuilderOption; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.psi.PsiClass; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiField; import com.intellij.psi.PsiMethod; @@ -10,7 +9,6 @@ import com.intellij.psi.util.PsiUtil; import java.util.Objects; -import java.util.Optional; import java.util.stream.Collectors; class BuilderMethodsGenerator extends AbstractGenerator implements MethodsGenerator { @@ -56,48 +54,42 @@ private PsiMethod generateValidateMethod() { } private PsiMethod generateFieldMethod(PsiField field) { - var addMethod = field.hasInitializer() ? findAddMethod(field) : null; + var addMethod = field.hasInitializer() ? Utils.findAddMethod(field) : null; if (null != addMethod) { return generateAddToCollection(field, addMethod); } - return generateBuilderSetter(field); - } - private PsiMethod findAddMethod(PsiField field) { - if (isFieldInitializedWithImmutableCollection(field)) { - return null; - } - var fieldClass = PsiUtil.resolveClassInClassTypeOnly(field.getType()); - var methods = Optional.ofNullable(fieldClass) - .map(PsiClass::getAllMethods) - .orElseGet(() -> new PsiMethod[0]); - for (var method : methods) { - if (method.getName().equals("add") && method.getParameterList().getParametersCount() == 1) { - return method; - } + var putMethod = field.hasInitializer() ? Utils.findPutMethod(field) : null; + if (null != putMethod) { + return generatePutToMap(field, putMethod); } - return null; + + return generateBuilderSetter(field); } - private boolean isFieldInitializedWithImmutableCollection(PsiField field) { - var initializer = field.getInitializer(); - if (null == initializer) { - return false; - } - var initializerType = initializer.getType(); - if (null == initializerType) { - return false; - } - var initializerClass = PsiUtil.resolveClassInClassTypeOnly(initializerType); - return null != initializerClass && initializerClass.hasModifierProperty(PsiModifier.ABSTRACT); + private PsiMethod generatePutToMap(PsiField field, PsiMethod fieldPutMethod) { + //resolve the generic type of the map via the parameter type of the put method + var param1 = Objects.requireNonNull(fieldPutMethod.getParameterList().getParameter(0)); + var param1Type = Utils.resolveGenericParameterType(field.getType(), param1); + var param2 = Objects.requireNonNull(fieldPutMethod.getParameterList().getParameter(1)); + var param2Type = Utils.resolveGenericParameterType(field.getType(), param2); + + //now build the put method + var methodName = "putTo" + StringUtil.capitalize(field.getName()); + var methodText = """ + public %s %s(%s key, %s value) { + this.%s.put(key, value); + return this; + }""".formatted(BUILDER_CLASS_NAME, methodName, param1Type.getPresentableText(), + param2Type.getPresentableText(), field.getName()); + var psiElementFactory = generatorParams.psi().factory(); + return psiElementFactory.createMethodFromText(methodText, field); } private PsiMethod generateAddToCollection(PsiField field, PsiMethod fieldAddMethod) { //resolve the generic type of the collection via the parameter type of the add method var param = Objects.requireNonNull(fieldAddMethod.getParameterList().getParameter(0)); - var paramType = PsiUtil.resolveGenericsClassInType(field.getType()) - .getSubstitutor() - .substitute(param.getType()); + var paramType = Utils.resolveGenericParameterType(field.getType(), param); //now build the add method var methodName = "addTo" + StringUtil.capitalize(field.getName()); diff --git a/src/main/java/com/github/junkfactory/innerbuilder/generators/Utils.java b/src/main/java/com/github/junkfactory/innerbuilder/generators/Utils.java index f098952..0d0e621 100644 --- a/src/main/java/com/github/junkfactory/innerbuilder/generators/Utils.java +++ b/src/main/java/com/github/junkfactory/innerbuilder/generators/Utils.java @@ -2,19 +2,20 @@ import com.intellij.openapi.editor.Editor; import com.intellij.psi.PsiClass; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiElementFactory; +import com.intellij.psi.PsiField; import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiMethod; import com.intellij.psi.PsiModifier; +import com.intellij.psi.PsiParameter; import com.intellij.psi.PsiParameterList; -import com.intellij.psi.PsiStatement; import com.intellij.psi.PsiType; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.Optional; + public class Utils { @NonNls static final String JAVA_DOT_LANG = "java.lang."; @@ -84,8 +85,54 @@ public static PsiClass getStaticOrTopLevelClass(PsiFile file, Editor editor) { } } - static PsiStatement createReturnThis(@NotNull PsiElementFactory psiElementFactory, @Nullable PsiElement context) { - return psiElementFactory.createStatementFromText("return this;", context); + + @Nullable + public static PsiMethod findAddMethod(PsiField field) { + return findMethod(field, "add", 1); + } + + @Nullable + public static PsiMethod findPutMethod(PsiField field) { + return findMethod(field, "put", 2); + } + + @Nullable + public static PsiMethod findMethod(PsiField field, String methodName, int parameterCount) { + if (isFieldInitializedWithImmutableInstance(field)) { + return null; + } + var fieldClass = PsiUtil.resolveClassInClassTypeOnly(field.getType()); + var methods = Optional.ofNullable(fieldClass) + .map(PsiClass::getAllMethods) + .orElseGet(() -> new PsiMethod[0]); + for (var method : methods) { + if (method.getName().equals(methodName) && + method.getParameterList().getParametersCount() == parameterCount) { + return method; + } + } + return null; + } + + public static PsiType resolveGenericParameterType(PsiType fieldType, PsiParameter param) { + //resolve the generic type of the collection via the parameter type of the add method + return PsiUtil.resolveGenericsClassInType(fieldType) + .getSubstitutor() + .substitute(param.getType()); } + public static boolean isFieldInitializedWithImmutableInstance(PsiField field) { + var initializer = field.getInitializer(); + if (null == initializer) { + return false; + } + var initializerType = initializer.getType(); + if (null == initializerType) { + return false; + } + var initializerClass = PsiUtil.resolveClassInClassTypeOnly(initializerType); + return null != initializerClass && initializerClass.hasModifierProperty(PsiModifier.ABSTRACT); + } + + }