|
1 | 1 | package fr.adrienbrault.idea.symfony2plugin.stubs.indexes;
|
2 | 2 |
|
3 | 3 | import com.intellij.openapi.vfs.VfsUtil;
|
4 |
| -import com.intellij.psi.PsiElement; |
5 | 4 | import com.intellij.psi.PsiFile;
|
6 |
| -import com.intellij.psi.PsiRecursiveElementVisitor; |
7 |
| -import com.intellij.psi.util.PsiTreeUtil; |
8 | 5 | import com.intellij.util.ObjectUtils;
|
9 | 6 | import com.intellij.util.containers.HashSet;
|
10 | 7 | import com.intellij.util.indexing.*;
|
11 | 8 | import com.intellij.util.io.DataExternalizer;
|
12 | 9 | import com.intellij.util.io.EnumeratorStringDescriptor;
|
13 | 10 | import com.intellij.util.io.KeyDescriptor;
|
| 11 | +import com.jetbrains.php.codeInsight.controlFlow.PhpInstructionProcessor; |
| 12 | +import com.jetbrains.php.codeInsight.controlFlow.instructions.PhpAccessVariableInstruction; |
| 13 | +import com.jetbrains.php.codeInsight.controlFlow.instructions.PhpInstruction; |
14 | 14 | import com.jetbrains.php.lang.PhpFileType;
|
15 | 15 | import com.jetbrains.php.lang.psi.PhpFile;
|
16 |
| -import com.jetbrains.php.lang.psi.elements.*; |
| 16 | +import com.jetbrains.php.lang.psi.elements.Method; |
| 17 | +import com.jetbrains.php.lang.psi.elements.MethodReference; |
| 18 | +import com.jetbrains.php.lang.psi.elements.Parameter; |
| 19 | +import com.jetbrains.php.lang.psi.elements.PhpClass; |
17 | 20 | import fr.adrienbrault.idea.symfony2plugin.Symfony2ProjectComponent;
|
18 | 21 | import fr.adrienbrault.idea.symfony2plugin.dic.container.dict.ContainerBuilderCall;
|
19 | 22 | import fr.adrienbrault.idea.symfony2plugin.stubs.indexes.externalizer.ObjectStreamDataExternalizer;
|
20 | 23 | import fr.adrienbrault.idea.symfony2plugin.util.PhpElementsUtil;
|
21 | 24 | import gnu.trove.THashMap;
|
| 25 | +import one.util.streamex.StreamEx; |
22 | 26 | import org.apache.commons.lang.StringUtils;
|
23 | 27 | import org.jetbrains.annotations.NotNull;
|
24 | 28 |
|
@@ -69,8 +73,10 @@ public DataIndexer<String, ContainerBuilderCall, FileContent> getIndexer() {
|
69 | 73 | return map;
|
70 | 74 | }
|
71 | 75 |
|
72 |
| - psiFile.accept(new MyPsiRecursiveElementWalkingVisitor(map)); |
73 |
| - |
| 76 | + StreamEx.of(((PhpFile) psiFile).getTopLevelDefs().values()) |
| 77 | + .select(PhpClass.class) |
| 78 | + .flatMap(clazz -> StreamEx.of(clazz.getOwnMethods())) |
| 79 | + .forEach(method -> processMethod(method, map)); |
74 | 80 | return map;
|
75 | 81 | };
|
76 | 82 | }
|
@@ -130,89 +136,52 @@ private static boolean isValidForIndex(FileContent inputData, PsiFile psiFile) {
|
130 | 136 | return true;
|
131 | 137 | }
|
132 | 138 |
|
133 |
| - private class MyPsiRecursiveElementWalkingVisitor extends PsiRecursiveElementVisitor { |
134 |
| - |
135 |
| - private final Map<String, ContainerBuilderCall> map; |
136 |
| - |
137 |
| - MyPsiRecursiveElementWalkingVisitor(@NotNull Map<String, ContainerBuilderCall> map) { |
138 |
| - this.map = map; |
139 |
| - } |
140 |
| - |
141 |
| - @Override |
142 |
| - public void visitElement(PsiElement element) { |
143 |
| - if(!(element instanceof Parameter)) { |
144 |
| - super.visitElement(element); |
145 |
| - return; |
146 |
| - } |
147 |
| - |
148 |
| - ClassReference classReference = ObjectUtils.tryCast(element.getFirstChild(), ClassReference.class); |
149 |
| - if(classReference == null) { |
150 |
| - return; |
151 |
| - } |
152 |
| - |
153 |
| - String fqn = StringUtils.stripStart(classReference.getFQN(), "\\"); |
154 |
| - if(!SET.contains(fqn)) { |
155 |
| - return; |
156 |
| - } |
157 |
| - |
158 |
| - Parameter parentOfType = PsiTreeUtil.getParentOfType(classReference, Parameter.class); |
159 |
| - if(parentOfType == null) { |
160 |
| - return; |
161 |
| - } |
162 |
| - |
163 |
| - final String name = parentOfType.getName(); |
164 |
| - |
165 |
| - Method method = PsiTreeUtil.getParentOfType(classReference, Method.class); |
166 |
| - if(method == null) { |
167 |
| - return; |
168 |
| - } |
169 |
| - |
170 |
| - method.accept(new MyMethodVariableVisitor(name, map)); |
171 |
| - |
172 |
| - super.visitElement(element); |
| 139 | + private void processMethod(@NotNull Method method, @NotNull Map<String, ContainerBuilderCall> map) { |
| 140 | + Set<CharSequence> containerParameters = StreamEx.of(method.getParameters()) |
| 141 | + .filter(ContainerBuilderStubIndex::isContainerParam) |
| 142 | + .map(Parameter::getNameCS) |
| 143 | + .toSet(); |
| 144 | + if (containerParameters.isEmpty()) return; |
| 145 | + MyInstructionProcessor processor = new MyInstructionProcessor(map, containerParameters); |
| 146 | + for (PhpInstruction instruction : method.getControlFlow().getInstructions()) { |
| 147 | + instruction.process(processor); |
173 | 148 | }
|
174 | 149 | }
|
175 | 150 |
|
176 |
| - private class MyMethodVariableVisitor extends PsiRecursiveElementVisitor { |
| 151 | + private static boolean isContainerParam(@NotNull Parameter parameter) { |
| 152 | + String parameterType = parameter.getDeclaredType().toString(); |
| 153 | + return SET.contains(StringUtils.stripStart(parameterType, "\\")); |
| 154 | + } |
177 | 155 |
|
| 156 | + private static class MyInstructionProcessor extends PhpInstructionProcessor { |
178 | 157 | @NotNull
|
179 |
| - private final String name; |
180 |
| - |
| 158 | + private final Map<String, ContainerBuilderCall> map; |
181 | 159 | @NotNull
|
182 |
| - private final Map<String, ContainerBuilderCall> result; |
| 160 | + private final Set<CharSequence> containerParameters; |
183 | 161 |
|
184 |
| - MyMethodVariableVisitor(@NotNull String name, @NotNull Map<String, ContainerBuilderCall> result) { |
185 |
| - this.name = name; |
186 |
| - this.result = result; |
| 162 | + MyInstructionProcessor(@NotNull Map<String, ContainerBuilderCall> map, |
| 163 | + @NotNull Set<CharSequence> containerParameters) { |
| 164 | + this.map = map; |
| 165 | + this.containerParameters = containerParameters; |
187 | 166 | }
|
188 |
| - |
| 167 | + |
189 | 168 | @Override
|
190 |
| - public void visitElement(PsiElement element) { |
191 |
| - if(!(element instanceof Variable) || !name.equals(((Variable) element).getName())) { |
192 |
| - super.visitElement(element); |
193 |
| - return; |
194 |
| - } |
195 |
| - |
196 |
| - MethodReference methodReference = ObjectUtils.tryCast(element.getParent(), MethodReference.class); |
197 |
| - if(methodReference == null || !METHODS.contains(methodReference.getName())) { |
198 |
| - super.visitElement(element); |
199 |
| - return; |
200 |
| - } |
201 |
| - |
| 169 | + public boolean processAccessVariableInstruction(PhpAccessVariableInstruction instruction) { |
| 170 | + if (!instruction.getAccess().isRead() || |
| 171 | + !containerParameters.contains(instruction.getVariableName())) return true; |
| 172 | + |
| 173 | + MethodReference methodReference = |
| 174 | + ObjectUtils.tryCast(instruction.getAnchor().getParent(), MethodReference.class); |
| 175 | + if (methodReference == null || !METHODS.contains(methodReference.getName())) return true; |
| 176 | + |
202 | 177 | String value = PhpElementsUtil.getFirstArgumentStringValue(methodReference);
|
203 |
| - if(value == null) { |
204 |
| - super.visitElement(element); |
205 |
| - return; |
206 |
| - } |
207 |
| - |
| 178 | + if (value == null) return true; |
| 179 | + |
208 | 180 | String methodName = methodReference.getName();
|
209 |
| - if(!result.containsKey(methodName)) { |
210 |
| - result.put(methodName, new ContainerBuilderCall()); |
211 |
| - } |
212 |
| - |
213 |
| - result.get(methodName).addParameter(value); |
214 |
| - |
215 |
| - super.visitElement(element); |
| 181 | + map.computeIfAbsent(methodName, name -> new ContainerBuilderCall()); |
| 182 | + map.get(methodName).addParameter(value); |
| 183 | + |
| 184 | + return true; |
216 | 185 | }
|
217 | 186 | }
|
218 | 187 | }
|
0 commit comments