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
.codeInsight
;
18 import com
.intellij
.codeInsight
.completion
.JavaCompletionUtil
;
19 import com
.intellij
.lang
.StdLanguages
;
20 import com
.intellij
.openapi
.application
.ApplicationManager
;
21 import com
.intellij
.openapi
.editor
.Editor
;
22 import com
.intellij
.openapi
.fileEditor
.FileEditorManager
;
23 import com
.intellij
.openapi
.fileEditor
.OpenFileDescriptor
;
24 import com
.intellij
.openapi
.progress
.ProgressManager
;
25 import com
.intellij
.openapi
.project
.Project
;
26 import com
.intellij
.openapi
.util
.Computable
;
27 import com
.intellij
.openapi
.util
.Condition
;
28 import com
.intellij
.openapi
.util
.TextRange
;
29 import com
.intellij
.psi
.*;
30 import com
.intellij
.psi
.search
.GlobalSearchScope
;
31 import com
.intellij
.psi
.search
.searches
.ClassInheritorsSearch
;
32 import com
.intellij
.psi
.tree
.IElementType
;
33 import com
.intellij
.psi
.util
.PsiTreeUtil
;
34 import com
.intellij
.psi
.util
.PsiUtil
;
35 import com
.intellij
.psi
.util
.TypeConversionUtil
;
36 import com
.intellij
.psi
.util
.proximity
.PsiProximityComparator
;
37 import com
.intellij
.refactoring
.util
.RefactoringUtil
;
38 import com
.intellij
.util
.FilteredQuery
;
39 import com
.intellij
.util
.Processor
;
40 import com
.intellij
.util
.Query
;
41 import org
.jetbrains
.annotations
.NotNull
;
42 import org
.jetbrains
.annotations
.Nullable
;
49 public class CodeInsightUtil
{
51 public static PsiExpression
findExpressionInRange(PsiFile file
, int startOffset
, int endOffset
) {
52 if (!file
.getViewProvider().getLanguages().contains(StdLanguages
.JAVA
)) return null;
53 PsiExpression expression
= findElementInRange(file
, startOffset
, endOffset
, PsiExpression
.class);
54 if (expression
== null && findStatementsInRange(file
, startOffset
, endOffset
).length
== 0) {
55 PsiElement element2
= file
.getViewProvider().findElementAt(endOffset
- 1, StdLanguages
.JAVA
);
56 if (element2
instanceof PsiJavaToken
) {
57 final PsiJavaToken token
= (PsiJavaToken
)element2
;
58 final IElementType tokenType
= token
.getTokenType();
59 if (tokenType
.equals(JavaTokenType
.SEMICOLON
)) {
60 expression
= findElementInRange(file
, startOffset
, element2
.getTextRange().getStartOffset(), PsiExpression
.class);
64 if (expression
instanceof PsiReferenceExpression
&& expression
.getParent() instanceof PsiMethodCallExpression
) return null;
68 public static <T
extends PsiElement
> T
findElementInRange(PsiFile file
, int startOffset
, int endOffset
, Class
<T
> klass
) {
69 return CodeInsightUtilBase
.findElementInRange(file
, startOffset
, endOffset
, klass
, StdLanguages
.JAVA
);
73 public static PsiElement
[] findStatementsInRange(@NotNull PsiFile file
, int startOffset
, int endOffset
) {
74 FileViewProvider viewProvider
= file
.getViewProvider();
75 if (!viewProvider
.getLanguages().contains(StdLanguages
.JAVA
)) return PsiElement
.EMPTY_ARRAY
;
76 PsiElement element1
= viewProvider
.findElementAt(startOffset
, StdLanguages
.JAVA
);
77 PsiElement element2
= viewProvider
.findElementAt(endOffset
- 1, StdLanguages
.JAVA
);
78 if (element1
instanceof PsiWhiteSpace
) {
79 startOffset
= element1
.getTextRange().getEndOffset();
80 element1
= file
.findElementAt(startOffset
);
82 if (element2
instanceof PsiWhiteSpace
) {
83 endOffset
= element2
.getTextRange().getStartOffset();
84 element2
= file
.findElementAt(endOffset
- 1);
86 if (element1
== null || element2
== null) return PsiElement
.EMPTY_ARRAY
;
88 PsiElement parent
= PsiTreeUtil
.findCommonParent(element1
, element2
);
89 if (parent
== null) return PsiElement
.EMPTY_ARRAY
;
91 if (parent
instanceof PsiStatement
) {
92 parent
= parent
.getParent();
95 if (parent
instanceof PsiCodeBlock
) break;
96 if (JspPsiUtil
.isInJspFile(parent
) && parent
instanceof PsiFile
) break;
97 if (parent
instanceof PsiCodeFragment
) break;
98 if (parent
== null || parent
instanceof PsiFile
) return PsiElement
.EMPTY_ARRAY
;
99 parent
= parent
.getParent();
102 if (!parent
.equals(element1
)) {
103 while (!parent
.equals(element1
.getParent())) {
104 element1
= element1
.getParent();
107 if (startOffset
!= element1
.getTextRange().getStartOffset()) return PsiElement
.EMPTY_ARRAY
;
109 if (!parent
.equals(element2
)) {
110 while (!parent
.equals(element2
.getParent())) {
111 element2
= element2
.getParent();
114 if (endOffset
!= element2
.getTextRange().getEndOffset()) return PsiElement
.EMPTY_ARRAY
;
116 if (parent
instanceof PsiCodeBlock
&& parent
.getParent() instanceof PsiBlockStatement
&&
117 element1
== ((PsiCodeBlock
)parent
).getLBrace() && element2
== ((PsiCodeBlock
)parent
).getRBrace()) {
118 return new PsiElement
[]{parent
.getParent()};
122 if(parent instanceof PsiCodeBlock && parent.getParent() instanceof PsiBlockStatement) {
123 return new PsiElement[]{parent.getParent()};
127 PsiElement
[] children
= parent
.getChildren();
128 ArrayList
<PsiElement
> array
= new ArrayList
<PsiElement
>();
129 boolean flag
= false;
130 for (PsiElement child
: children
) {
131 if (child
.equals(element1
)) {
134 if (flag
&& !(child
instanceof PsiWhiteSpace
)) {
137 if (child
.equals(element2
)) {
142 for (PsiElement element
: array
) {
143 if (!(element
instanceof PsiStatement
|| element
instanceof PsiWhiteSpace
|| element
instanceof PsiComment
)) {
144 return PsiElement
.EMPTY_ARRAY
;
148 return array
.toArray(new PsiElement
[array
.size()]);
151 public static void sortIdenticalShortNameClasses(PsiClass
[] classes
, @NotNull PsiElement context
) {
152 if (classes
.length
<= 1) return;
154 Arrays
.sort(classes
, new PsiProximityComparator(context
));
157 public static PsiExpression
[] findExpressionOccurrences(PsiElement scope
, PsiExpression expr
) {
158 List
<PsiExpression
> array
= new ArrayList
<PsiExpression
>();
159 addExpressionOccurrences(RefactoringUtil
.unparenthesizeExpression(expr
), array
, scope
);
160 return array
.toArray(new PsiExpression
[array
.size()]);
163 private static void addExpressionOccurrences(PsiExpression expr
, List
<PsiExpression
> array
, PsiElement scope
) {
164 PsiElement
[] children
= scope
.getChildren();
165 for (PsiElement child
: children
) {
166 if (child
instanceof PsiExpression
) {
167 if (areExpressionsEquivalent(RefactoringUtil
.unparenthesizeExpression((PsiExpression
)child
), expr
)) {
168 array
.add((PsiExpression
)child
);
172 addExpressionOccurrences(expr
, array
, child
);
176 public static PsiExpression
[] findReferenceExpressions(PsiElement scope
, PsiElement referee
) {
177 ArrayList
<PsiElement
> array
= new ArrayList
<PsiElement
>();
178 addReferenceExpressions(array
, scope
, referee
);
179 return array
.toArray(new PsiExpression
[array
.size()]);
182 private static void addReferenceExpressions(ArrayList
<PsiElement
> array
, PsiElement scope
, PsiElement referee
) {
183 PsiElement
[] children
= scope
.getChildren();
184 for (PsiElement child
: children
) {
185 if (child
instanceof PsiReferenceExpression
) {
186 PsiElement ref
= ((PsiReferenceExpression
)child
).resolve();
187 if (ref
!= null && PsiEquivalenceUtil
.areElementsEquivalent(ref
, referee
)) {
191 addReferenceExpressions(array
, child
, referee
);
195 public static boolean areExpressionsEquivalent(PsiExpression expr1
, PsiExpression expr2
) {
196 return PsiEquivalenceUtil
.areElementsEquivalent(expr1
, expr2
);
199 public static Editor
positionCursor(final Project project
, PsiFile targetFile
, PsiElement element
) {
200 TextRange range
= element
.getTextRange();
201 int textOffset
= range
.getStartOffset();
203 OpenFileDescriptor descriptor
= new OpenFileDescriptor(project
, targetFile
.getVirtualFile(), textOffset
);
204 return FileEditorManager
.getInstance(project
).openTextEditor(descriptor
, true);
207 public static boolean preparePsiElementsForWrite(@NotNull PsiElement
... elements
) {
208 return CodeInsightUtilBase
.preparePsiElementsForWrite(Arrays
.asList(elements
));
211 public static Set
<PsiType
> addSubtypes(PsiType psiType
, final PsiElement context
,
212 final boolean getRawSubtypes
, Condition
<String
> shortNameCondition
) {
213 int arrayDim
= psiType
.getArrayDimensions();
215 psiType
= psiType
.getDeepComponentType();
216 if (!(psiType
instanceof PsiClassType
)) return Collections
.emptySet();
219 final PsiClassType baseType
= (PsiClassType
)psiType
;
220 final PsiClassType
.ClassResolveResult baseResult
=
221 ApplicationManager
.getApplication().runReadAction(new Computable
<PsiClassType
.ClassResolveResult
>() {
222 public PsiClassType
.ClassResolveResult
compute() {
223 return JavaCompletionUtil
.originalize(baseType
).resolveGenerics();
226 final PsiClass baseClass
= baseResult
.getElement();
227 final PsiSubstitutor baseSubstitutor
= baseResult
.getSubstitutor();
228 if(baseClass
== null) return Collections
.emptySet();
230 Set
<PsiType
> result
= new HashSet
<PsiType
>();
231 final GlobalSearchScope scope
= ApplicationManager
.getApplication().runReadAction(new Computable
<GlobalSearchScope
>() {
232 public GlobalSearchScope
compute() {
233 return context
.getResolveScope();
236 final Query
<PsiClass
> baseQuery
= ClassInheritorsSearch
.search(
237 new ClassInheritorsSearch
.SearchParameters(baseClass
, scope
, true, false, false, shortNameCondition
));
238 final Query
<PsiClass
> query
= new FilteredQuery
<PsiClass
>(baseQuery
, new Condition
<PsiClass
>() {
239 public boolean value(final PsiClass psiClass
) {
240 return !(psiClass
instanceof PsiTypeParameter
);
244 query
.forEach(createInheritorsProcessor(context
, baseType
, arrayDim
, getRawSubtypes
, result
, baseClass
, baseSubstitutor
));
248 public static Processor
<PsiClass
> createInheritorsProcessor(final PsiElement context
, final PsiClassType baseType
,
250 final boolean getRawSubtypes
,
251 final Set
<PsiType
> result
, @NotNull final PsiClass baseClass
, final PsiSubstitutor baseSubstitutor
) {
252 final PsiManager manager
= context
.getManager();
253 final JavaPsiFacade facade
= JavaPsiFacade
.getInstance(manager
.getProject());
254 final PsiResolveHelper resolveHelper
= facade
.getResolveHelper();
256 return new Processor
<PsiClass
>() {
257 public boolean process(final PsiClass inheritor
) {
258 ProgressManager
.checkCanceled();
260 return ApplicationManager
.getApplication().runReadAction(new Computable
<Boolean
>() {
261 public Boolean
compute() {
262 if (!context
.isValid() || !inheritor
.isValid() || !facade
.getResolveHelper().isAccessible(inheritor
, context
, null)) return true;
264 if(inheritor
.getQualifiedName() == null && !manager
.areElementsEquivalent(inheritor
.getContainingFile(), context
.getContainingFile().getOriginalFile())){
268 if (JavaCompletionUtil
.isInExcludedPackage(inheritor
)) return true;
270 PsiSubstitutor superSubstitutor
= TypeConversionUtil
.getClassSubstitutor(baseClass
, inheritor
, PsiSubstitutor
.EMPTY
);
271 if(superSubstitutor
== null) return true;
273 result
.add(createType(inheritor
, facade
.getElementFactory().createRawSubstitutor(inheritor
), arrayDim
));
277 PsiSubstitutor inheritorSubstitutor
= PsiSubstitutor
.EMPTY
;
278 for (PsiTypeParameter inheritorParameter
: PsiUtil
.typeParametersIterable(inheritor
)) {
279 for (PsiTypeParameter baseParameter
: PsiUtil
.typeParametersIterable(baseClass
)) {
280 final PsiType substituted
= superSubstitutor
.substitute(baseParameter
);
281 PsiType arg
= baseSubstitutor
.substitute(baseParameter
);
282 if (arg
instanceof PsiWildcardType
) arg
= ((PsiWildcardType
)arg
).getExtendsBound();
283 PsiType substitution
= resolveHelper
.getSubstitutionForTypeParameter(inheritorParameter
,
287 PsiUtil
.getLanguageLevel(context
));
288 if (PsiType
.NULL
.equals(substitution
) || substitution
instanceof PsiWildcardType
) continue;
289 if (substitution
== null) {
290 result
.add(createType(inheritor
, facade
.getElementFactory().createRawSubstitutor(inheritor
), arrayDim
));
293 inheritorSubstitutor
= inheritorSubstitutor
.put(inheritorParameter
, substitution
);
298 PsiType toAdd
= createType(inheritor
, inheritorSubstitutor
, arrayDim
);
299 if (baseType
.isAssignableFrom(toAdd
)) {
309 private static PsiType
createType(PsiClass cls
,
310 PsiSubstitutor currentSubstitutor
,
312 final PsiElementFactory elementFactory
= JavaPsiFacade
.getInstance(cls
.getProject()).getElementFactory();
313 PsiType newType
= elementFactory
.createType(cls
, currentSubstitutor
);
314 for(int i
= 0; i
< arrayDim
; i
++){
315 newType
= newType
.createArrayType();