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
;
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();
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) {
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) {
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
) {
91 myCheckDeep
= checkDeep
;
92 myCheckInheritance
= checkInheritance
;
93 myIncludeAnonymous
= includeAnonymous
;
94 myNameCondition
= nameCondition
;
98 public PsiClass
getClassToProcess() {
102 public Condition
<String
> getNameCondition() {
103 return myNameCondition
;
106 public boolean isCheckDeep() {
110 public SearchScope
getScope() {
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() {
181 if (parameters
.isCheckInheritance() || parameters
.isCheckDeep() && !(candidate
instanceof PsiAnonymousClass
)) {
182 if (!candidate
.isInheritor(currentBase
.get(), false)) {
188 if (PsiSearchScopeUtil
.isInScope(searchScope
, candidate
)) {
189 if (candidate
instanceof PsiAnonymousClass
) {
190 result
.set(consumer
.process(candidate
));
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
);
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;
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
));