rename: remember 'Search for text occurrences' checkbox state (IDEA-21328)
[fedora-idea.git] / java / java-impl / src / com / intellij / codeInsight / CodeInsightUtil.java
blob1472f8dae11ffd07568f34928b052a50371fb4ce
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.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;
44 import java.util.*;
46 /**
49 public class CodeInsightUtil {
50 @Nullable
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;
65 return expression;
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);
72 @NotNull
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;
90 while (true) {
91 if (parent instanceof PsiStatement) {
92 parent = parent.getParent();
93 break;
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)) {
132 flag = true;
134 if (flag && !(child instanceof PsiWhiteSpace)) {
135 array.add(child);
137 if (child.equals(element2)) {
138 break;
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);
169 continue;
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)) {
188 array.add(child);
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));
245 return result;
248 public static Processor<PsiClass> createInheritorsProcessor(final PsiElement context, final PsiClassType baseType,
249 final int arrayDim,
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())){
265 return true;
268 if (JavaCompletionUtil.isInExcludedPackage(inheritor)) return true;
270 PsiSubstitutor superSubstitutor = TypeConversionUtil.getClassSubstitutor(baseClass, inheritor, PsiSubstitutor.EMPTY);
271 if(superSubstitutor == null) return true;
272 if(getRawSubtypes){
273 result.add(createType(inheritor, facade.getElementFactory().createRawSubstitutor(inheritor), arrayDim));
274 return true;
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,
284 substituted,
285 arg,
286 true,
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));
291 return true;
293 inheritorSubstitutor = inheritorSubstitutor.put(inheritorParameter, substitution);
294 break;
298 PsiType toAdd = createType(inheritor, inheritorSubstitutor, arrayDim);
299 if (baseType.isAssignableFrom(toAdd)) {
300 result.add(toAdd);
302 return true;
304 }).booleanValue();
309 private static PsiType createType(PsiClass cls,
310 PsiSubstitutor currentSubstitutor,
311 int arrayDim) {
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();
317 return newType;