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
;
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
);
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
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
);
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
)) {
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
);
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
]);
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;
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
);
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
);
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
);
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();
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
)) {
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
);