Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,13 @@

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;
import com.intellij.psi.PsiModifier;
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 {
Expand Down Expand Up @@ -56,32 +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);
}

var putMethod = field.hasInitializer() ? Utils.findPutMethod(field) : null;
if (null != putMethod) {
return generatePutToMap(field, putMethod);
}

return generateBuilderSetter(field);
}

private PsiMethod findAddMethod(PsiField field) {
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;
}
}
return null;
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());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.";
Expand Down Expand Up @@ -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);
}


}