Skip to content

Commit aefb624

Browse files
committed
use children visitor for voter string collector instead of references which are too slow #431
1 parent 9a00b05 commit aefb624

File tree

2 files changed

+95
-71
lines changed

2 files changed

+95
-71
lines changed

src/fr/adrienbrault/idea/symfony2plugin/security/utils/VoterUtil.java

+53-71
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,13 @@
44
import com.intellij.openapi.util.Pair;
55
import com.intellij.psi.PsiElement;
66
import com.intellij.psi.PsiFile;
7-
import com.intellij.psi.PsiReference;
87
import com.intellij.psi.search.FilenameIndex;
98
import com.intellij.psi.search.GlobalSearchScope;
109
import com.intellij.psi.tree.IElementType;
1110
import com.intellij.psi.util.PsiTreeUtil;
12-
import com.intellij.util.CommonProcessors;
1311
import com.jetbrains.php.PhpIndex;
1412
import com.jetbrains.php.lang.lexer.PhpTokenTypes;
1513
import com.jetbrains.php.lang.parser.PhpElementTypes;
16-
import com.jetbrains.php.lang.psi.PhpPsiUtil;
1714
import com.jetbrains.php.lang.psi.elements.*;
1815
import fr.adrienbrault.idea.symfony2plugin.util.PhpElementsUtil;
1916
import fr.adrienbrault.idea.symfony2plugin.util.yaml.YamlHelper;
@@ -123,11 +120,9 @@ private static void visitAttribute(@NotNull Method method, @NotNull Consumer<Pai
123120
return;
124121
}
125122

126-
PhpPsiUtil.hasReferencesInSearchScope(
127-
method.getUseScope(),
128-
parameters[0],
129-
new MyAttributePsiReferenceFindProcessor(consumer)
130-
);
123+
for (Variable variable : PhpElementsUtil.getVariablesInScope(method, parameters[0])) {
124+
visitVariable(variable, consumer);
125+
}
131126
}
132127

133128
public static class StringPairConsumer implements Consumer<Pair<String, PsiElement>> {
@@ -171,84 +166,71 @@ public Set<PsiElement> getValues() {
171166
/**
172167
* Find security roles on Voter implementation and security roles in Yaml
173168
*/
174-
private static class MyAttributePsiReferenceFindProcessor extends CommonProcessors.FindProcessor<PsiReference> {
175-
private final Consumer<Pair<String, PsiElement>> consumer;
176-
177-
MyAttributePsiReferenceFindProcessor(Consumer<Pair<String, PsiElement>> consumer) {
178-
this.consumer = consumer;
179-
}
180-
181-
@Override
182-
protected boolean accept(PsiReference psiReference) {
183-
PsiElement resolve = psiReference.getElement();
184-
185-
PsiElement parent = resolve.getParent();
186-
if(parent instanceof BinaryExpression) {
187-
// 'VALUE' == $var
188-
PsiElement rightElement = PsiTreeUtil.prevVisibleLeaf(resolve);
189-
if(rightElement != null) {
190-
IElementType node = rightElement.getNode().getElementType();
191-
if(isIfOperand(node)) {
192-
PsiElement leftOperand = ((BinaryExpression) parent).getLeftOperand();
193-
String stringValue = PhpElementsUtil.getStringValue(leftOperand);
194-
if(StringUtils.isNotBlank(stringValue)) {
195-
consumer.accept(Pair.create(stringValue, leftOperand));
196-
}
169+
private static void visitVariable(@NotNull Variable resolve, @NotNull Consumer<Pair<String, PsiElement>> consumer) {
170+
PsiElement parent = resolve.getParent();
171+
if(parent instanceof BinaryExpression) {
172+
// 'VALUE' == $var
173+
PsiElement rightElement = PsiTreeUtil.prevVisibleLeaf(resolve);
174+
if(rightElement != null) {
175+
IElementType node = rightElement.getNode().getElementType();
176+
if(isIfOperand(node)) {
177+
PsiElement leftOperand = ((BinaryExpression) parent).getLeftOperand();
178+
String stringValue = PhpElementsUtil.getStringValue(leftOperand);
179+
if(StringUtils.isNotBlank(stringValue)) {
180+
consumer.accept(Pair.create(stringValue, leftOperand));
197181
}
198182
}
183+
}
199184

200-
// $var == 'VALUE'
201-
PsiElement leftElement = PsiTreeUtil.nextVisibleLeaf(resolve);
202-
if(leftElement != null) {
203-
IElementType node = leftElement.getNode().getElementType();
204-
if(isIfOperand(node)) {
205-
PsiElement rightOperand = ((BinaryExpression) parent).getRightOperand();
206-
String stringValue = PhpElementsUtil.getStringValue(rightOperand);
207-
if(StringUtils.isNotBlank(stringValue)) {
208-
consumer.accept(Pair.create(stringValue, rightOperand));
209-
}
185+
// $var == 'VALUE'
186+
PsiElement leftElement = PsiTreeUtil.nextVisibleLeaf(resolve);
187+
if(leftElement != null) {
188+
IElementType node = leftElement.getNode().getElementType();
189+
if(isIfOperand(node)) {
190+
PsiElement rightOperand = ((BinaryExpression) parent).getRightOperand();
191+
String stringValue = PhpElementsUtil.getStringValue(rightOperand);
192+
if(StringUtils.isNotBlank(stringValue)) {
193+
consumer.accept(Pair.create(stringValue, rightOperand));
210194
}
211195
}
212-
} else if(parent instanceof ParameterList) {
213-
// in_array($x, ['FOOBAR'])
214-
PsiElement functionCall = parent.getParent();
215-
if(functionCall instanceof FunctionReference && "in_array".equalsIgnoreCase(((FunctionReference) functionCall).getName())) {
216-
PsiElement[] functionParameter = ((ParameterList) parent).getParameters();
217-
if(functionParameter.length > 1 && functionParameter[1] instanceof ArrayCreationExpression) {
218-
PsiElement[] psiElements = PsiTreeUtil.collectElements(functionParameter[1], psiElement -> psiElement.getNode().getElementType() == PhpElementTypes.ARRAY_VALUE);
219-
for (PsiElement psiElement : psiElements) {
220-
PsiElement firstChild = psiElement.getFirstChild();
221-
String stringValue = PhpElementsUtil.getStringValue(firstChild);
222-
if(StringUtils.isNotBlank(stringValue)) {
223-
consumer.accept(Pair.create(stringValue, firstChild));
224-
}
196+
}
197+
} else if(parent instanceof ParameterList) {
198+
// in_array($x, ['FOOBAR'])
199+
PsiElement functionCall = parent.getParent();
200+
if(functionCall instanceof FunctionReference && "in_array".equalsIgnoreCase(((FunctionReference) functionCall).getName())) {
201+
PsiElement[] functionParameter = ((ParameterList) parent).getParameters();
202+
if(functionParameter.length > 1 && functionParameter[1] instanceof ArrayCreationExpression) {
203+
PsiElement[] psiElements = PsiTreeUtil.collectElements(functionParameter[1], psiElement -> psiElement.getNode().getElementType() == PhpElementTypes.ARRAY_VALUE);
204+
for (PsiElement psiElement : psiElements) {
205+
PsiElement firstChild = psiElement.getFirstChild();
206+
String stringValue = PhpElementsUtil.getStringValue(firstChild);
207+
if(StringUtils.isNotBlank(stringValue)) {
208+
consumer.accept(Pair.create(stringValue, firstChild));
225209
}
226210
}
227211
}
228-
} else if(parent instanceof PhpSwitch) {
229-
// case "foobar":
230-
for (PhpCase phpCase : ((PhpSwitch) parent).getAllCases()) {
231-
PhpPsiElement condition = phpCase.getCondition();
232-
String stringValue = PhpElementsUtil.getStringValue(condition);
233-
if(StringUtils.isNotBlank(stringValue)) {
234-
consumer.accept(Pair.create(stringValue, condition));
235-
}
212+
}
213+
} else if(parent instanceof PhpSwitch) {
214+
// case "foobar":
215+
for (PhpCase phpCase : ((PhpSwitch) parent).getAllCases()) {
216+
PhpPsiElement condition = phpCase.getCondition();
217+
String stringValue = PhpElementsUtil.getStringValue(condition);
218+
if(StringUtils.isNotBlank(stringValue)) {
219+
consumer.accept(Pair.create(stringValue, condition));
236220
}
237221
}
238-
239-
return false;
240222
}
223+
}
241224

242-
/**
243-
* null == null, null != null, null === null
244-
*/
245-
private boolean isIfOperand(@NotNull IElementType node) {
246-
return
247-
node == PhpTokenTypes.opIDENTICAL ||
225+
/**
226+
* null == null, null != null, null === null
227+
*/
228+
private static boolean isIfOperand(@NotNull IElementType node) {
229+
return
230+
node == PhpTokenTypes.opIDENTICAL ||
248231
node == PhpTokenTypes.opEQUAL ||
249232
node == PhpTokenTypes.opNOT_EQUAL ||
250233
node == PhpTokenTypes.opNOT_IDENTICAL
251234
;
252-
}
253235
}
254236
}

src/fr/adrienbrault/idea/symfony2plugin/util/PhpElementsUtil.java

+42
Original file line numberDiff line numberDiff line change
@@ -1385,4 +1385,46 @@ public static String insertUseIfNecessary(@NotNull PsiElement phpClass, @NotNull
13851385
return null;
13861386
}
13871387

1388+
/**
1389+
* Collects all variables in a given scope.
1390+
* Eg find all variables usages in a given method
1391+
*/
1392+
@NotNull
1393+
public static Set<Variable> getVariablesInScope(@NotNull PsiElement psiElement, @NotNull PhpNamedElement variable) {
1394+
return MyVariableRecursiveElementVisitor.visit(psiElement, variable.getName());
1395+
}
1396+
1397+
@NotNull
1398+
public static Set<Variable> getVariablesInScope(@NotNull PsiElement psiElement, @NotNull String name) {
1399+
return MyVariableRecursiveElementVisitor.visit(psiElement, name);
1400+
}
1401+
1402+
/**
1403+
* Visit and collect all variables in given scope
1404+
*/
1405+
private static class MyVariableRecursiveElementVisitor extends PsiRecursiveElementVisitor {
1406+
@NotNull
1407+
private final String name;
1408+
1409+
@NotNull
1410+
private final Set<Variable> variables = new HashSet<>();
1411+
1412+
MyVariableRecursiveElementVisitor(@NotNull String name) {
1413+
this.name = name;
1414+
}
1415+
1416+
@Override
1417+
public void visitElement(PsiElement element) {
1418+
if(element instanceof Variable && name.equals(((Variable) element).getName())) {
1419+
variables.add((Variable) element);
1420+
}
1421+
super.visitElement(element);
1422+
}
1423+
1424+
public static Set<Variable> visit(@NotNull PsiElement scope, @NotNull String name) {
1425+
MyVariableRecursiveElementVisitor visitor = new MyVariableRecursiveElementVisitor(name);
1426+
scope.acceptChildren(visitor);
1427+
return visitor.variables;
1428+
}
1429+
}
13881430
}

0 commit comments

Comments
 (0)