Skip to content

Commit 3fed859

Browse files
authored
Merge pull request #1526 from Haehnchen/feature/form-builder-code-flow
use simple code flow for formBuilder field extraction
2 parents 70994f1 + ce8d9fb commit 3fed859

File tree

3 files changed

+125
-14
lines changed

3 files changed

+125
-14
lines changed

src/main/java/fr/adrienbrault/idea/symfony2plugin/form/util/FormUtil.java

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import com.intellij.openapi.project.Project;
77
import com.intellij.psi.PsiElement;
88
import com.intellij.psi.impl.source.xml.XmlDocumentImpl;
9+
import com.intellij.psi.util.PsiElementFilter;
910
import com.intellij.psi.util.PsiTreeUtil;
1011
import com.intellij.psi.xml.XmlAttribute;
1112
import com.intellij.psi.xml.XmlFile;
@@ -80,25 +81,54 @@ public static Collection<LookupElement> getFormTypeLookupElements(Project projec
8081
return lookupElements;
8182
}
8283

83-
public static MethodReference[] getFormBuilderTypes(Method method) {
84-
List<MethodReference> methodReferences = new ArrayList<>();
85-
86-
PsiTreeUtil.collectElements(method, methodReference -> {
84+
public static MethodReference[] getFormBuilderTypes(@NotNull Method method) {
85+
PsiElementFilter filter = methodReference -> {
8786
if (methodReference instanceof MethodReference) {
8887
String methodName = ((MethodReference) methodReference).getName();
8988
if (methodName != null && (methodName.equals("add") || methodName.equals("create"))) {
90-
if(PhpElementsUtil.isMethodReferenceInstanceOf((MethodReference) methodReference, FormUtil.PHP_FORM_BUILDER_SIGNATURES)) {
91-
methodReferences.add((MethodReference) methodReference);
92-
return true;
93-
}
89+
return PhpElementsUtil.isMethodReferenceInstanceOf((MethodReference) methodReference, FormUtil.PHP_FORM_BUILDER_SIGNATURES);
9490
}
9591
}
9692

9793
return false;
98-
});
94+
};
95+
96+
Collection<PsiElement> methodReferences = new HashSet<>(Arrays.asList(PsiTreeUtil.collectElements(method, filter)));
97+
98+
// some code flow detection for sub methods
99+
if ("buildForm".equals(method.getName())) {
100+
for (Parameter parameter : method.getParameters()) {
101+
boolean isFormBuilder = parameter.getType().getTypes().stream()
102+
.noneMatch(s -> StringUtils.stripStart(s, "\\").equalsIgnoreCase("Symfony\\Component\\Form\\FormBuilderInterface"));
103+
104+
if (isFormBuilder) {
105+
continue;
106+
}
107+
108+
String text = parameter.getName();
109+
PsiElement[] psiElements = PsiTreeUtil.collectElements(method, psiElement -> psiElement instanceof Variable && text.equals(((Variable) psiElement).getName()));
99110

100-
return methodReferences.toArray(new MethodReference[methodReferences.size()]);
111+
for (PsiElement psiElement : psiElements) {
112+
PsiElement parameterList = psiElement.getParent();
113+
if (!(parameterList instanceof ParameterList)) {
114+
continue;
115+
}
116+
PsiElement methodReference = parameterList.getParent();
117+
if (!(methodReference instanceof MethodReference)) {
118+
continue;
119+
}
120+
121+
PsiElement resolve = ((MethodReference) methodReference).resolve();
122+
if (!(resolve instanceof Method)) {
123+
continue;
124+
}
125+
126+
Collections.addAll(methodReferences, PsiTreeUtil.collectElements(resolve, filter));
127+
}
128+
}
129+
}
101130

131+
return methodReferences.stream().map(psiElement -> (MethodReference) psiElement).toArray(MethodReference[]::new);
102132
}
103133

104134
/**

src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/form/util/FormUtilTest.java

Lines changed: 63 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
package fr.adrienbrault.idea.symfony2plugin.tests.form.util;
22

33
import com.jetbrains.php.lang.psi.PhpPsiElementFactory;
4+
import com.jetbrains.php.lang.psi.elements.Method;
45
import com.jetbrains.php.lang.psi.elements.PhpClass;
6+
import com.jetbrains.php.lang.psi.elements.StringLiteralExpression;
57
import com.jetbrains.php.lang.psi.elements.impl.ClassConstantReferenceImpl;
68
import com.jetbrains.php.lang.psi.elements.impl.PhpTypedElementImpl;
79
import com.jetbrains.php.lang.psi.elements.impl.StringLiteralExpressionImpl;
810
import fr.adrienbrault.idea.symfony2plugin.form.dict.FormTypeClass;
911
import fr.adrienbrault.idea.symfony2plugin.form.util.FormUtil;
1012
import fr.adrienbrault.idea.symfony2plugin.tests.SymfonyLightCodeInsightFixtureTestCase;
1113

12-
import java.util.ArrayList;
13-
import java.util.Arrays;
14-
import java.util.Collection;
15-
import java.util.Map;
14+
import java.util.*;
15+
import java.util.stream.Collectors;
1616

1717
/**
1818
* @author Daniel Espendiller <daniel@espendiller.net>
@@ -288,4 +288,63 @@ public void testGetFormExtendedTypesAsYield() {
288288

289289
assertContainsElements(FormUtil.getFormExtendedType(phpClass), "Foobar", "test");
290290
}
291+
292+
public void testThatFormFieldsOfBuildFormForGetFormBuilderTypes() {
293+
Method method = PhpPsiElementFactory.createFromText(getProject(), Method.class, "<?php\n" +
294+
"class Foobar\n" +
295+
"{\n" +
296+
" public public function buildForm(\\Symfony\\Component\\Form\\FormBuilderInterface $builder, array $options)\n" +
297+
" {\n" +
298+
" $builder\n" +
299+
" ->add('task', TextType::class)\n" +
300+
" ->add('dueDate', DateType::class)\n" +
301+
" ->add('save', SubmitType::class)\n" +
302+
" ;" +
303+
" }\n" +
304+
"}\n"
305+
);
306+
307+
Set<String> collect = Arrays.stream(FormUtil.getFormBuilderTypes(method))
308+
.map(methodReference -> ((StringLiteralExpression) Objects.requireNonNull(methodReference.getParameter(0))).getContents())
309+
.collect(Collectors.toSet());
310+
311+
assertContainsElements(collect, "task");
312+
assertContainsElements(collect, "dueDate");
313+
assertContainsElements(collect, "save");
314+
}
315+
316+
public void testThatFormFieldsOfBuildFormForGetFormBuilderTypesForCodeFlow() {
317+
Method method = PhpPsiElementFactory.createFromText(getProject(), Method.class, "<?php\n" +
318+
"class Foobar\n" +
319+
"{\n" +
320+
" public function foo(array $options, \\Symfony\\Component\\Form\\FormBuilderInterface $builder2)\n" +
321+
" {\n" +
322+
" $builder2->add('builder2');\n" +
323+
" $builder->addEventListener('foo', function (\\Symfony\\Component\\Form\\FormEvent $event) {\n" +
324+
" $form = $event->getForm();\n" +
325+
" $form->add('email2');\n" +
326+
" });" +
327+
" }\n" +
328+
" public public function buildForm(\\Symfony\\Component\\Form\\FormBuilderInterface $builder, array $options)\n" +
329+
" {\n" +
330+
" $builder->addEventListener('foo', function (\\Symfony\\Component\\Form\\FormEvent $event) {\n" +
331+
" $form = $event->getForm();\n" +
332+
" $form->add('email');\n" +
333+
" });" +
334+
" $builder->add('task', TextType::class);\n" +
335+
" $this->foo([], $builder);\n" +
336+
" }\n" +
337+
"}\n"
338+
);
339+
340+
Set<String> collect = Arrays.stream(FormUtil.getFormBuilderTypes(method))
341+
.map(methodReference -> ((StringLiteralExpression) Objects.requireNonNull(methodReference.getParameter(0))).getContents())
342+
.collect(Collectors.toSet());
343+
344+
assertContainsElements(collect, "email");
345+
assertContainsElements(collect, "task");
346+
347+
assertContainsElements(collect, "email2");
348+
assertContainsElements(collect, "builder2");
349+
}
291350
}

src/test/java/fr/adrienbrault/idea/symfony2plugin/tests/form/util/fixtures/classes.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,26 @@ public function getName()
2626
namespace Symfony\Component\Form
2727
{
2828
interface FormTypeInterface {}
29+
interface FormBuilderInterface
30+
{
31+
/**
32+
* @return FormBuilderInterface
33+
*/
34+
public function add();
35+
}
36+
37+
interface FormInterface {
38+
public function add();
39+
public function create();
40+
}
41+
42+
class FormEvent extends Event
43+
{
44+
/**
45+
* @return FormInterface
46+
*/
47+
public function getForm()
48+
{
49+
}
50+
}
2951
}

0 commit comments

Comments
 (0)