Skip to content

Commit 788c866

Browse files
authored
Optimizations (#7)
* Remove document commit * Invoke post document processing * Use string in user data * Use createField/MethodFromText and StringBuilder * Short circuit field collections * Use StringBuilder in inner class builder
1 parent b7fbe05 commit 788c866

File tree

7 files changed

+191
-143
lines changed

7 files changed

+191
-143
lines changed

src/main/java/com/github/junkfactory/innerbuilder/JavaInnerBuilderHandler.java

Lines changed: 35 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.github.junkfactory.innerbuilder;
22

3+
import com.github.junkfactory.innerbuilder.generators.FieldCollector;
34
import com.github.junkfactory.innerbuilder.generators.GeneratorFactory;
45
import com.github.junkfactory.innerbuilder.generators.GeneratorParams;
56
import com.github.junkfactory.innerbuilder.generators.PsiParams;
@@ -13,15 +14,14 @@
1314
import com.intellij.openapi.fileEditor.FileDocumentManager;
1415
import com.intellij.openapi.project.Project;
1516
import com.intellij.psi.JavaPsiFacade;
16-
import com.intellij.psi.PsiDocumentManager;
1717
import com.intellij.psi.PsiFile;
1818
import com.intellij.psi.PsiJavaFile;
19+
import com.intellij.util.AstLoadingFilter;
1920
import org.jetbrains.annotations.NotNull;
2021

2122
import java.util.EnumSet;
2223
import java.util.Set;
2324

24-
import static com.github.junkfactory.innerbuilder.generators.FieldCollector.collectFields;
2525
import static com.github.junkfactory.innerbuilder.ui.JavaInnerBuilderOptionSelector.selectFieldsAndOptions;
2626

2727
class JavaInnerBuilderHandler implements LanguageCodeInsightActionHandler {
@@ -48,19 +48,15 @@ public boolean startInWriteAction() {
4848
}
4949

5050
private static boolean isApplicable(final PsiFile file, final Editor editor) {
51-
var targetElements = collectFields(file, editor);
52-
return !targetElements.isEmpty();
51+
return FieldCollector.builder()
52+
.file(file)
53+
.editor(editor)
54+
.build()
55+
.hasFields();
5356
}
5457

5558
@Override
5659
public void invoke(@NotNull final Project project, @NotNull final Editor editor, @NotNull final PsiFile file) {
57-
var psiDocumentManager = PsiDocumentManager.getInstance(project);
58-
var currentDocument = psiDocumentManager.getDocument(file);
59-
if (currentDocument == null) {
60-
return;
61-
}
62-
63-
psiDocumentManager.commitDocument(currentDocument);
6460

6561
if (!EditorModificationUtil.checkModificationAllowed(editor)) {
6662
return;
@@ -70,29 +66,37 @@ public void invoke(@NotNull final Project project, @NotNull final Editor editor,
7066
return;
7167
}
7268

73-
var existingFields = collectFields(file, editor);
74-
if (existingFields.isEmpty()) {
75-
return;
76-
}
77-
78-
var selectedFields = selectFieldsAndOptions(existingFields, project);
79-
if (selectedFields.isEmpty()) {
80-
return;
81-
}
82-
83-
var psiParams = PsiParams.builder()
69+
var fieldCollector = FieldCollector.builder()
8470
.file(file)
85-
.selectedFields(selectedFields)
86-
.factory(JavaPsiFacade.getElementFactory(project))
87-
.build();
88-
var generatorParams = GeneratorParams.builder()
89-
.project(project)
9071
.editor(editor)
91-
.psi(psiParams)
92-
.options(currentOptions())
9372
.build();
94-
var builderGenerator = generatorFactory.createInnerBuilderGenerator(generatorParams);
95-
ApplicationManager.getApplication().runWriteAction(builderGenerator);
73+
74+
AstLoadingFilter.disallowTreeLoading(() -> {
75+
var existingFields = fieldCollector.collectFields();
76+
if (existingFields.isEmpty()) {
77+
return;
78+
}
79+
80+
var selectedFields = selectFieldsAndOptions(existingFields, project);
81+
if (selectedFields.isEmpty()) {
82+
return;
83+
}
84+
85+
var psiParams = PsiParams.builder()
86+
.file(file)
87+
.selectedFields(selectedFields)
88+
.factory(JavaPsiFacade.getElementFactory(project))
89+
.build();
90+
var generatorParams = GeneratorParams.builder()
91+
.project(project)
92+
.editor(editor)
93+
.psi(psiParams)
94+
.options(currentOptions())
95+
.build();
96+
var builderGenerator = generatorFactory.createInnerBuilderGenerator(generatorParams);
97+
ApplicationManager.getApplication().runWriteAction(builderGenerator);
98+
});
99+
96100
}
97101

98102
private Set<JavaInnerBuilderOption> currentOptions() {

src/main/java/com/github/junkfactory/innerbuilder/generators/AbstractGenerator.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ abstract class AbstractGenerator implements Runnable {
1515
static final String BUILDER_METHOD_NAME = "builder";
1616
@NonNls
1717
static final String TO_BUILDER_NAME = "toBuilder";
18+
@NonNls
19+
static final String EMPTY = "";
20+
@NonNls
21+
static final String SPACE = " ";
1822

1923
protected final GeneratorFactory generatorFactory;
2024
protected final GeneratorParams generatorParams;

src/main/java/com/github/junkfactory/innerbuilder/generators/BuilderFieldsGenerator.java

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88

99
import java.util.LinkedList;
1010
import java.util.List;
11-
import java.util.Optional;
1211

1312
class BuilderFieldsGenerator extends AbstractGenerator implements FieldsGenerator {
1413

@@ -68,9 +67,13 @@ private void deleteFieldAndMethodIfExists(PsiClass builderClass, PsiField field)
6867
if (null == field) {
6968
return;
7069
}
71-
Optional.ofNullable(field.getCopyableUserData(UserDataKey.METHOD_REF))
72-
.map(m -> builderClass.findMethodBySignature(m, false))
73-
.ifPresent(PsiElement::delete);
70+
var methodName = field.getCopyableUserData(UserDataKey.METHOD_REF);
71+
if (null != methodName) {
72+
var builderClassMethods = builderClass.findMethodsByName(methodName, false);
73+
for (var method : builderClassMethods) {
74+
method.delete();
75+
}
76+
}
7477
field.delete();
7578
}
7679

src/main/java/com/github/junkfactory/innerbuilder/generators/BuilderMethodsGenerator.java

Lines changed: 35 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,11 @@
77
import com.intellij.psi.PsiField;
88
import com.intellij.psi.PsiMethod;
99
import com.intellij.psi.PsiModifier;
10-
import com.intellij.psi.PsiStatement;
1110
import com.intellij.psi.util.PsiUtil;
1211

1312
import java.util.Objects;
1413
import java.util.Optional;
1514
import java.util.stream.Collectors;
16-
import java.util.stream.Stream;
1715

1816
class BuilderMethodsGenerator extends AbstractGenerator implements MethodsGenerator {
1917

@@ -35,7 +33,7 @@ public void run() {
3533
PsiElement lastAddedElement = null;
3634
for (var field : fieldsGenerator.getFields()) {
3735
var setterMethod = generateFieldMethod(field);
38-
field.putCopyableUserData(UserDataKey.METHOD_REF, setterMethod);
36+
field.putCopyableUserData(UserDataKey.METHOD_REF, setterMethod.getName());
3937
lastAddedElement = addMethod(builderClass, lastAddedElement, setterMethod, false);
4038
}
4139

@@ -86,74 +84,61 @@ private PsiMethod generateAddToCollection(PsiField field, PsiMethod fieldAddMeth
8684
.substitute(param.getType());
8785

8886
//now build the add method
89-
var fieldName = "addTo" + StringUtil.capitalize(field.getName());
87+
var methodName = "addTo" + StringUtil.capitalize(field.getName());
88+
var methodText = """
89+
public %s %s(%s %s) {
90+
this.%s.add(%s);
91+
return this;
92+
}""".formatted(BUILDER_CLASS_NAME, methodName, paramType.getPresentableText(),
93+
param.getName().toLowerCase(), field.getName(), param.getName());
9094
var psiElementFactory = generatorParams.psi().factory();
91-
var addMethod = psiElementFactory.createMethod(fieldName, builderClassParams.builderType());
92-
PsiUtil.setModifierProperty(addMethod, PsiModifier.PUBLIC, true);
93-
94-
var addParameter = psiElementFactory.createParameter(param.getName().toLowerCase(), paramType);
95-
addMethod.getParameterList().add(addParameter);
96-
97-
var addMethodBody = Objects.requireNonNull(addMethod.getBody());
98-
var addBody = psiElementFactory.createStatementFromText(String.format(
99-
"this.%s.add(%s);", field.getName(), param.getName()), addMethod);
100-
addMethodBody.add(addBody);
101-
addMethodBody.add(Utils.createReturnThis(psiElementFactory, addMethod));
102-
return addMethod;
95+
return psiElementFactory.createMethodFromText(methodText, field);
10396
}
10497

10598
private PsiMethod generateBuilderSetter(PsiField field) {
10699
var fieldType = field.getType();
107100
var fieldName = Utils.hasOneLetterPrefix(field.getName()) ?
108101
Character.toLowerCase(field.getName().charAt(1)) + field.getName().substring(2) : field.getName();
109102

103+
var methodText = """
104+
public %s %s(%s %s) {
105+
this.%s = %s;
106+
return this;
107+
}""".formatted(BUILDER_CLASS_NAME, fieldName, fieldType.getPresentableText(),
108+
fieldName, field.getName(), fieldName);
110109
var psiElementFactory = generatorParams.psi().factory();
111-
var setterMethod = psiElementFactory.createMethod(fieldName, builderClassParams.builderType());
112-
setterMethod.getModifierList().setModifierProperty(PsiModifier.PUBLIC, true);
113-
114-
var setterParameter = psiElementFactory.createParameter(fieldName, fieldType);
115-
setterMethod.getParameterList().add(setterParameter);
116-
117-
var setterMethodBody = Objects.requireNonNull(setterMethod.getBody());
118-
var actualFieldName = "this." + fieldName;
119-
var assignStatement = psiElementFactory.createStatementFromText(String.format(
120-
"%s = %s;", actualFieldName, fieldName), setterMethod);
121-
setterMethodBody.add(assignStatement);
122-
setterMethodBody.add(Utils.createReturnThis(psiElementFactory, setterMethod));
123-
return setterMethod;
110+
return psiElementFactory.createMethodFromText(methodText, field);
124111
}
125112

126113
private PsiMethod generateBuildMethod() {
127114
var targetClass = builderClassParams.targetClass();
128-
var psiElementFactory = generatorParams.psi().factory();
129-
var targetClassType = psiElementFactory.createType(targetClass);
130-
var buildMethod = psiElementFactory.createMethod("build", targetClassType);
131-
132115
var targetModifierList = Objects.requireNonNull(targetClass.getModifierList());
133-
Stream.of(PsiModifier.PUBLIC, PsiModifier.PACKAGE_LOCAL)
134-
.filter(targetModifierList::hasModifierProperty)
135-
.findFirst()
136-
.ifPresent(modifier -> PsiUtil.setModifierProperty(buildMethod, modifier, true));
116+
boolean isPublic = targetModifierList.hasModifierProperty(PsiModifier.PUBLIC);
137117

138-
var buildMethodBody = Objects.requireNonNull(buildMethod.getBody());
118+
var buildMethod = new StringBuilder()
119+
.append(isPublic ? PsiModifier.PUBLIC : EMPTY)
120+
.append(isPublic ? SPACE : EMPTY)
121+
.append(targetClass.getName())
122+
.append(" build() {");
139123
if (generatorParams.options().contains(JavaInnerBuilderOption.WITH_VALIDATE_METHOD)) {
140-
var validateCall = psiElementFactory.createStatementFromText("validate();", buildMethod);
141-
buildMethodBody.add(validateCall);
124+
buildMethod.append("validate();");
142125
}
143-
144-
final PsiStatement returnStatement;
145126
if (targetClass.isRecord()) {
146-
var recordParameters = generatorParams.psi().selectedFields().stream()
147-
.map(m -> m.getElement().getName())
127+
var recordParameters = fieldsGenerator.getFields().stream()
128+
.map(PsiField::getName)
148129
.collect(Collectors.joining(", "));
149-
returnStatement = psiElementFactory.createStatementFromText(String.format(
150-
"return new %s(%s);", targetClass.getName(), recordParameters), buildMethod);
130+
buildMethod.append("return new ")
131+
.append(targetClass.getName())
132+
.append("(")
133+
.append(recordParameters)
134+
.append(");");
151135
} else {
152-
returnStatement = psiElementFactory.createStatementFromText(String.format(
153-
"return new %s(this);", targetClass.getName()), buildMethod);
136+
buildMethod.append("return new ")
137+
.append(targetClass.getName())
138+
.append("(this);");
154139
}
140+
buildMethod.append("}");
155141

156-
buildMethodBody.add(returnStatement);
157-
return buildMethod;
142+
return generatorParams.psi().factory().createMethodFromText(buildMethod.toString(), targetClass);
158143
}
159144
}

0 commit comments

Comments
 (0)