IDEA-50121
[fedora-idea.git] / java / java-impl / src / com / intellij / slicer / forward / SliceFUtil.java
blob903cf3e4c24dff4f894c15e552c0cc2f2a7b9695
1 /*
2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com.intellij.slicer.forward;
18 import com.intellij.openapi.util.Pair;
19 import com.intellij.psi.*;
20 import com.intellij.psi.search.searches.MethodReferencesSearch;
21 import com.intellij.psi.search.searches.OverridingMethodsSearch;
22 import com.intellij.psi.search.searches.ReferencesSearch;
23 import com.intellij.psi.util.MethodSignatureUtil;
24 import com.intellij.psi.util.PsiTreeUtil;
25 import com.intellij.slicer.SliceDereferenceUsage;
26 import com.intellij.slicer.SliceManager;
27 import com.intellij.slicer.SliceUsage;
28 import com.intellij.slicer.SliceUtil;
29 import com.intellij.util.ArrayUtil;
30 import com.intellij.util.Processor;
31 import gnu.trove.THashSet;
32 import org.jetbrains.annotations.NotNull;
33 import org.jetbrains.annotations.Nullable;
35 import java.util.Arrays;
36 import java.util.Collection;
37 import java.util.Iterator;
38 import java.util.Set;
40 /**
41 * @author cdr
43 public class SliceFUtil {
44 public static boolean processUsagesFlownFromThe(@NotNull PsiElement element, @NotNull final Processor<SliceUsage> processor, @NotNull final SliceUsage parent) {
45 Pair<PsiElement, PsiSubstitutor> pair = getAssignmentTarget(element, parent);
46 if (pair != null) {
47 PsiElement target = pair.getFirst();
48 final PsiSubstitutor substitutor = pair.getSecond();
49 if (target instanceof PsiParameter) {
50 PsiParameter parameter = (PsiParameter)target;
51 PsiElement declarationScope = parameter.getDeclarationScope();
52 if (declarationScope instanceof PsiMethod) {
53 final PsiMethod method = (PsiMethod)declarationScope;
54 final int parameterIndex = method.getParameterList().getParameterIndex(parameter);
56 Processor<PsiMethod> myProcessor = new Processor<PsiMethod>() {
57 public boolean process(PsiMethod override) {
58 if (!parent.getScope().contains(override)) return true;
59 final PsiSubstitutor superSubstitutor = method == override
60 ? substitutor
61 : MethodSignatureUtil.getSuperMethodSignatureSubstitutor(method.getSignature(substitutor),
62 override.getSignature(substitutor));
64 PsiParameter[] parameters = override.getParameterList().getParameters();
65 if (parameters.length <= parameterIndex) return true;
66 PsiParameter actualParam = parameters[parameterIndex];
68 SliceUsage usage = SliceUtil.createSliceUsage(actualParam, parent, superSubstitutor);
69 return processor.process(usage);
72 if (!myProcessor.process(method)) return false;
73 return OverridingMethodsSearch.search(method, parent.getScope().toSearchScope(), true).forEach(myProcessor);
77 SliceUsage usage = SliceUtil.createSliceUsage(target, parent, parent.getSubstitutor());
78 return processor.process(usage);
81 if (element instanceof PsiReferenceExpression) {
82 PsiReferenceExpression ref = (PsiReferenceExpression)element;
83 PsiElement resolved = ref.resolve();
84 if (!(resolved instanceof PsiVariable)) return true;
85 final PsiVariable variable = (PsiVariable)resolved;
86 return processAssignedFrom(variable, ref, parent, processor);
88 if (element instanceof PsiVariable) {
89 return processAssignedFrom(element, element, parent, processor);
91 if (element instanceof PsiMethod) {
92 return processAssignedFrom(element, element, parent, processor);
94 return true;
97 private static boolean processAssignedFrom(final PsiElement from, final PsiElement context, final SliceUsage parent,
98 final Processor<SliceUsage> processor) {
99 if (from instanceof PsiLocalVariable) {
100 return searchReferencesAndProcessAssignmentTarget(from, context, parent, processor);
102 if (from instanceof PsiParameter) {
103 PsiParameter parameter = (PsiParameter)from;
104 PsiElement scope = parameter.getDeclarationScope();
105 Collection<PsiParameter> parametersToAnalyze = new THashSet<PsiParameter>();
106 if (scope instanceof PsiMethod) {
107 final PsiMethod method = (PsiMethod)scope;
108 int index = method.getParameterList().getParameterIndex(parameter);
110 Collection<PsiMethod> superMethods = new THashSet<PsiMethod>(Arrays.asList(method.findDeepestSuperMethods()));
111 superMethods.add(method);
112 for (Iterator<PsiMethod> iterator = superMethods.iterator(); iterator.hasNext(); ) {
113 SliceManager.getInstance(method.getProject()).checkCanceled();
114 PsiMethod superMethod = iterator.next();
115 if (!parent.params.scope.contains(superMethod)) {
116 iterator.remove();
120 final THashSet<PsiMethod> implementors = new THashSet<PsiMethod>(superMethods);
121 for (PsiMethod superMethod : superMethods) {
122 SliceManager.getInstance(method.getProject()).checkCanceled();
123 if (!OverridingMethodsSearch.search(superMethod, parent.getScope().toSearchScope(), true).forEach(new Processor<PsiMethod>() {
124 public boolean process(PsiMethod sub) {
125 SliceManager.getInstance(method.getProject()).checkCanceled();
126 implementors.add(sub);
127 return true;
129 })) return false;
131 for (PsiMethod implementor : implementors) {
132 SliceManager.getInstance(method.getProject()).checkCanceled();
133 if (!parent.params.scope.contains(implementor)) continue;
134 if (implementor instanceof PsiCompiledElement) implementor = (PsiMethod)implementor.getNavigationElement();
136 PsiParameter[] parameters = implementor.getParameterList().getParameters();
137 if (index != -1 && index < parameters.length) {
138 parametersToAnalyze.add(parameters[index]);
142 else {
143 parametersToAnalyze.add(parameter);
145 for (final PsiParameter psiParameter : parametersToAnalyze) {
146 SliceManager.getInstance(from.getProject()).checkCanceled();
148 if (!searchReferencesAndProcessAssignmentTarget(psiParameter, null, parent, processor)) return false;
150 return true;
152 if (from instanceof PsiField) {
153 return searchReferencesAndProcessAssignmentTarget(from, null, parent, processor);
156 if (from instanceof PsiMethod) {
157 PsiMethod method = (PsiMethod)from;
159 Collection<PsiMethod> superMethods = new THashSet<PsiMethod>(Arrays.asList(method.findDeepestSuperMethods()));
160 superMethods.add(method);
161 final Set<PsiReference> processed = new THashSet<PsiReference>(); //usages of super method and overridden method can overlap
162 for (final PsiMethod containingMethod : superMethods) {
163 if (!MethodReferencesSearch.search(containingMethod, parent.getScope().toSearchScope(), true).forEach(new Processor<PsiReference>() {
164 public boolean process(final PsiReference reference) {
165 SliceManager.getInstance(from.getProject()).checkCanceled();
166 synchronized (processed) {
167 if (!processed.add(reference)) return true;
169 PsiElement element = reference.getElement().getParent();
171 return processAssignmentTarget(element, parent, processor);
173 })) {
174 return false;
178 return true;
181 private static boolean searchReferencesAndProcessAssignmentTarget(@NotNull PsiElement element, @Nullable final PsiElement context, final SliceUsage parent,
182 final Processor<SliceUsage> processor) {
183 return ReferencesSearch.search(element).forEach(new Processor<PsiReference>() {
184 public boolean process(PsiReference reference) {
185 PsiElement element = reference.getElement();
186 if (context != null && element.getTextOffset() < context.getTextOffset()) return true;
187 return processAssignmentTarget(element, parent, processor);
192 private static boolean processAssignmentTarget(PsiElement element, final SliceUsage parent, final Processor<SliceUsage> processor) {
193 if (!parent.params.scope.contains(element)) return true;
194 if (element instanceof PsiCompiledElement) element = element.getNavigationElement();
195 Pair<PsiElement, PsiSubstitutor> pair = getAssignmentTarget(element, parent);
196 if (pair != null) {
197 SliceUsage usage = SliceUtil.createSliceUsage(element, parent, pair.getSecond());
198 return processor.process(usage);
200 if (parent.params.showInstanceDereferences && isDereferenced(element)) {
201 SliceUsage usage = new SliceDereferenceUsage(element.getParent(), parent, parent.getSubstitutor());
202 return processor.process(usage);
204 return true;
207 private static boolean isDereferenced(PsiElement element) {
208 if (!(element instanceof PsiReferenceExpression)) return false;
209 PsiElement parent = element.getParent();
210 if (!(parent instanceof PsiReferenceExpression)) return false;
211 return ((PsiReferenceExpression)parent).getQualifierExpression() == element;
214 private static Pair<PsiElement,PsiSubstitutor> getAssignmentTarget(PsiElement element, SliceUsage parentUsage) {
215 element = complexify(element);
216 PsiElement target = null;
217 PsiSubstitutor substitutor = parentUsage.getSubstitutor();
218 //assignment
219 PsiElement parent = element.getParent();
220 if (parent instanceof PsiAssignmentExpression) {
221 PsiAssignmentExpression assignment = (PsiAssignmentExpression)parent;
222 if (element.equals(assignment.getRExpression())) {
223 PsiElement left = assignment.getLExpression();
224 if (left instanceof PsiReferenceExpression) {
225 JavaResolveResult result = ((PsiReferenceExpression)left).advancedResolve(false);
226 target = result.getElement();
227 substitutor = result.getSubstitutor();
231 else if (parent instanceof PsiVariable) {
232 PsiVariable variable = (PsiVariable)parent;
234 PsiElement initializer = variable.getInitializer();
235 if (element.equals(initializer)) {
236 target = variable;
239 //method call
240 else if (parent instanceof PsiExpressionList && parent.getParent() instanceof PsiCallExpression) {
241 PsiExpression[] expressions = ((PsiExpressionList)parent).getExpressions();
242 int index = ArrayUtil.find(expressions, element);
243 PsiCallExpression methodCall = (PsiCallExpression)parent.getParent();
244 JavaResolveResult result = methodCall.resolveMethodGenerics();
245 PsiMethod method = (PsiMethod)result.getElement();
246 if (index != -1 && method != null) {
247 PsiParameter[] parameters = method.getParameterList().getParameters();
248 if (index < parameters.length) {
249 target = parameters[index];
250 substitutor = result.getSubstitutor();
254 else if (parent instanceof PsiReturnStatement) {
255 PsiReturnStatement statement = (PsiReturnStatement)parent;
256 if (element.equals(statement.getReturnValue())) {
257 target = PsiTreeUtil.getParentOfType(statement, PsiMethod.class);
261 return target == null ? null : Pair.create(target, substitutor);
264 public static PsiElement complexify(@NotNull PsiElement element) {
265 PsiElement parent = element.getParent();
266 if (parent instanceof PsiParenthesizedExpression && element.equals(((PsiParenthesizedExpression)parent).getExpression())) {
267 return complexify(parent);
269 if (parent instanceof PsiTypeCastExpression && element.equals(((PsiTypeCastExpression)parent).getOperand())) {
270 return complexify(parent);
272 return element;