cleanup
[fedora-idea.git] / java / openapi / src / com / intellij / psi / search / searches / ClassInheritorsSearch.java
blob6a49e38206791734f7e5972bd7cbe61f8d7090b8
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.psi.search.searches;
18 import com.intellij.openapi.application.ApplicationManager;
19 import com.intellij.openapi.diagnostic.Logger;
20 import com.intellij.openapi.progress.ProgressIndicator;
21 import com.intellij.openapi.progress.ProgressManager;
22 import com.intellij.openapi.util.Computable;
23 import com.intellij.openapi.util.Condition;
24 import com.intellij.openapi.util.Ref;
25 import com.intellij.psi.*;
26 import com.intellij.psi.search.GlobalSearchScope;
27 import com.intellij.psi.search.PsiSearchScopeUtil;
28 import com.intellij.psi.search.SearchScope;
29 import com.intellij.util.Processor;
30 import com.intellij.util.Query;
31 import com.intellij.util.QueryExecutor;
32 import com.intellij.util.containers.Stack;
33 import org.jetbrains.annotations.NotNull;
35 import java.util.HashSet;
36 import java.util.Set;
38 /**
39 * @author max
41 public class ClassInheritorsSearch extends ExtensibleQueryFactory<PsiClass, ClassInheritorsSearch.SearchParameters> {
42 private static final Logger LOG = Logger.getInstance("#com.intellij.psi.search.searches.ClassInheritorsSearch");
44 public static final ClassInheritorsSearch INSTANCE = new ClassInheritorsSearch();
47 static {
48 INSTANCE.registerExecutor(new QueryExecutor<PsiClass, SearchParameters>() {
49 public boolean execute(final SearchParameters parameters, final Processor<PsiClass> consumer) {
50 final PsiClass baseClass = parameters.getClassToProcess();
51 final SearchScope searchScope = parameters.getScope();
53 LOG.assertTrue(searchScope != null);
55 ProgressIndicator progress = ProgressManager.getInstance().getProgressIndicator();
56 if (progress != null) {
57 progress.pushState();
58 String className = baseClass.getName();
59 progress.setText(className != null ?
60 PsiBundle.message("psi.search.inheritors.of.class.progress", className) :
61 PsiBundle.message("psi.search.inheritors.progress"));
64 boolean result = processInheritors(consumer, baseClass, searchScope, parameters);
66 if (progress != null) {
67 progress.popState();
70 return result;
72 });
75 public static class SearchParameters {
76 private final PsiClass myClass;
77 private final SearchScope myScope;
78 private final boolean myCheckDeep;
79 private final boolean myCheckInheritance;
80 private final boolean myIncludeAnonymous;
81 private final Condition<String> myNameCondition;
83 public SearchParameters(@NotNull final PsiClass aClass, @NotNull SearchScope scope, final boolean checkDeep, final boolean checkInheritance, boolean includeAnonymous) {
84 this(aClass, scope, checkDeep, checkInheritance, includeAnonymous, Condition.TRUE);
87 public SearchParameters(@NotNull final PsiClass aClass, @NotNull SearchScope scope, final boolean checkDeep, final boolean checkInheritance,
88 boolean includeAnonymous, final Condition<String> nameCondition) {
89 myClass = aClass;
90 myScope = scope;
91 myCheckDeep = checkDeep;
92 myCheckInheritance = checkInheritance;
93 myIncludeAnonymous = includeAnonymous;
94 myNameCondition = nameCondition;
97 @NotNull
98 public PsiClass getClassToProcess() {
99 return myClass;
102 public Condition<String> getNameCondition() {
103 return myNameCondition;
106 public boolean isCheckDeep() {
107 return myCheckDeep;
110 public SearchScope getScope() {
111 return myScope;
114 public boolean isCheckInheritance() {
115 return myCheckInheritance;
118 public boolean isIncludeAnonymous() {
119 return myIncludeAnonymous;
123 private ClassInheritorsSearch() {}
125 public static Query<PsiClass> search(@NotNull final PsiClass aClass, @NotNull SearchScope scope, final boolean checkDeep, final boolean checkInheritance, boolean includeAnonymous) {
126 return search(new SearchParameters(aClass, scope, checkDeep, checkInheritance, includeAnonymous));
129 public static Query<PsiClass> search(@NotNull SearchParameters parameters) {
130 return INSTANCE.createUniqueResultsQuery(parameters);
133 public static Query<PsiClass> search(@NotNull final PsiClass aClass, @NotNull SearchScope scope, final boolean checkDeep, final boolean checkInheritance) {
134 return search(aClass, scope, checkDeep, checkInheritance, true);
137 public static Query<PsiClass> search(@NotNull final PsiClass aClass, @NotNull SearchScope scope, final boolean checkDeep) {
138 return search(aClass, scope, checkDeep, true);
141 public static Query<PsiClass> search(@NotNull final PsiClass aClass, final boolean checkDeep) {
142 return search(aClass, aClass.getUseScope(), checkDeep);
145 public static Query<PsiClass> search(@NotNull PsiClass aClass) {
146 return search(aClass, true);
149 private static boolean processInheritors(@NotNull final Processor<PsiClass> consumer,
150 @NotNull final PsiClass baseClass,
151 @NotNull final SearchScope searchScope,
152 @NotNull final SearchParameters parameters) {
153 if (baseClass instanceof PsiAnonymousClass) return true;
155 if (isFinal(baseClass)) return true;
157 final String qname = ApplicationManager.getApplication().runReadAction(new Computable<String>() {
158 public String compute() {
159 return baseClass.getQualifiedName();
162 if (CommonClassNames.JAVA_LANG_OBJECT.equals(qname)) {
163 return AllClassesSearch.search(searchScope, baseClass.getProject(), parameters.getNameCondition()).forEach(new Processor<PsiClass>() {
164 public boolean process(PsiClass aClass) {
165 ProgressManager.checkCanceled();
166 return consumer.process(aClass);
171 final Ref<PsiClass> currentBase = Ref.create(null);
172 final Stack<PsiClass> stack = new Stack<PsiClass>();
173 final Set<PsiClass> processed = new HashSet<PsiClass>();
174 final Processor<PsiClass> processor = new Processor<PsiClass>() {
175 public boolean process(final PsiClass candidate) {
176 ProgressManager.checkCanceled();
178 final Ref<Boolean> result = new Ref<Boolean>();
179 ApplicationManager.getApplication().runReadAction(new Runnable() {
180 public void run() {
181 if (parameters.isCheckInheritance() || parameters.isCheckDeep() && !(candidate instanceof PsiAnonymousClass)) {
182 if (!candidate.isInheritor(currentBase.get(), false)) {
183 result.set(true);
184 return;
188 if (PsiSearchScopeUtil.isInScope(searchScope, candidate)) {
189 if (candidate instanceof PsiAnonymousClass) {
190 result.set(consumer.process(candidate));
192 else {
193 final String name = candidate.getName();
194 if (name != null && parameters.getNameCondition().value(name) && !consumer.process(candidate)) result.set(false);
199 if (!result.isNull()) return result.get().booleanValue();
201 if (parameters.isCheckDeep() && !(candidate instanceof PsiAnonymousClass) && !isFinal(candidate)) {
202 stack.push(candidate);
205 return true;
208 stack.push(baseClass);
209 final GlobalSearchScope scope = GlobalSearchScope.allScope(baseClass.getProject());
210 while (!stack.isEmpty()) {
211 ProgressManager.checkCanceled();
213 final PsiClass psiClass = stack.pop();
214 if (!processed.add(psiClass)) continue;
216 currentBase.set(psiClass);
217 if (!DirectClassInheritorsSearch.search(psiClass, scope, parameters.isIncludeAnonymous()).forEach(processor)) return false;
219 return true;
222 private static boolean isFinal(final PsiClass baseClass) {
223 return ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() {
224 public Boolean compute() {
225 return Boolean.valueOf(baseClass.hasModifierProperty(PsiModifier.FINAL));
227 }).booleanValue();