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
.impl
;
18 import com
.intellij
.openapi
.diagnostic
.Logger
;
19 import com
.intellij
.openapi
.roots
.ProjectFileIndex
;
20 import com
.intellij
.openapi
.roots
.ProjectRootManager
;
21 import com
.intellij
.openapi
.util
.*;
22 import com
.intellij
.openapi
.vfs
.VirtualFile
;
23 import com
.intellij
.psi
.*;
24 import com
.intellij
.psi
.filters
.OrFilter
;
25 import com
.intellij
.psi
.impl
.compiled
.ClsElementImpl
;
26 import com
.intellij
.psi
.impl
.source
.PsiImmediateClassType
;
27 import com
.intellij
.psi
.infos
.MethodCandidateInfo
;
28 import com
.intellij
.psi
.scope
.ElementClassFilter
;
29 import com
.intellij
.psi
.scope
.ElementClassHint
;
30 import com
.intellij
.psi
.scope
.NameHint
;
31 import com
.intellij
.psi
.scope
.PsiScopeProcessor
;
32 import com
.intellij
.psi
.scope
.processor
.FilterScopeProcessor
;
33 import com
.intellij
.psi
.scope
.processor
.MethodResolverProcessor
;
34 import com
.intellij
.psi
.search
.GlobalSearchScope
;
35 import com
.intellij
.psi
.search
.LocalSearchScope
;
36 import com
.intellij
.psi
.search
.PackageScope
;
37 import com
.intellij
.psi
.search
.SearchScope
;
38 import com
.intellij
.psi
.util
.*;
39 import com
.intellij
.ui
.IconDeferrer
;
40 import com
.intellij
.ui
.RowIcon
;
41 import com
.intellij
.util
.Function
;
42 import com
.intellij
.util
.IncorrectOperationException
;
43 import com
.intellij
.util
.ReflectionCache
;
44 import com
.intellij
.util
.SmartList
;
45 import com
.intellij
.util
.containers
.HashMap
;
46 import gnu
.trove
.THashSet
;
47 import org
.jetbrains
.annotations
.NonNls
;
48 import org
.jetbrains
.annotations
.NotNull
;
49 import org
.jetbrains
.annotations
.Nullable
;
55 * Created by IntelliJ IDEA.
59 * To change this template use Options | File Templates.
61 public class PsiClassImplUtil
{
62 private static final Logger LOG
= Logger
.getInstance("#com.intellij.psi.impl.PsiClassImplUtil");
63 private static final Key
<Boolean
> NAME_MAPS_BUILT_FLAG
= Key
.create("NAME_MAPS_BUILT_FLAG");
65 private static final Key
<CachedValue
<Map
>> MAP_IN_CLASS_KEY
= Key
.create("MAP_KEY");
67 @NotNull public static PsiField
[] getAllFields(final PsiClass aClass
) {
68 List
<PsiField
> map
= getAllByMap(aClass
, PsiField
.class);
69 return map
.toArray(new PsiField
[map
.size()]);
72 @NotNull public static PsiMethod
[] getAllMethods(final PsiClass aClass
) {
73 List
<PsiMethod
> methods
= getAllByMap(aClass
, PsiMethod
.class);
74 return methods
.toArray(new PsiMethod
[methods
.size()]);
77 @NotNull public static PsiClass
[] getAllInnerClasses(PsiClass aClass
) {
78 List
<PsiClass
> classes
= getAllByMap(aClass
, PsiClass
.class);
79 return classes
.toArray(new PsiClass
[classes
.size()]);
82 @Nullable public static PsiField
findFieldByName(PsiClass aClass
, String name
, boolean checkBases
) {
83 final List
<PsiField
> byMap
= findByMap(aClass
, name
, checkBases
, PsiField
.class);
84 return byMap
.isEmpty() ?
null : byMap
.get(0);
87 @NotNull public static PsiMethod
[] findMethodsByName(PsiClass aClass
, String name
, boolean checkBases
) {
88 List
<PsiMethod
> methods
= findByMap(aClass
, name
, checkBases
, PsiMethod
.class);
89 return methods
.toArray(new PsiMethod
[methods
.size()]);
92 @Nullable public static PsiMethod
findMethodBySignature(final PsiClass aClass
, final PsiMethod patternMethod
, final boolean checkBases
) {
93 final List
<PsiMethod
> result
= findMethodsBySignature(aClass
, patternMethod
, checkBases
, true);
94 return result
.isEmpty() ?
null : result
.get(0);
97 // ----------------------------- findMethodsBySignature -----------------------------------
99 @NotNull public static PsiMethod
[] findMethodsBySignature(final PsiClass aClass
, final PsiMethod patternMethod
, final boolean checkBases
) {
100 List
<PsiMethod
> methods
= findMethodsBySignature(aClass
, patternMethod
, checkBases
, false);
101 return methods
.toArray(new PsiMethod
[methods
.size()]);
104 @NotNull private static List
<PsiMethod
> findMethodsBySignature(final PsiClass aClass
,
105 final PsiMethod patternMethod
,
106 final boolean checkBases
,
107 final boolean stopOnFirst
) {
108 /* final MethodSignature patternSignature = MethodSignatureBackedByPsiMethod.create(patternMethod, PsiSubstitutor.EMPTY);
110 final PsiMethod[] methodsByName = aClass.findMethodsByName(patternMethod.getName(), false);
111 if (methodsByName.length == 0) return PsiMethod.EMPTY_ARRAY;
112 List<PsiMethod> result = new ArrayList<PsiMethod>();
113 for (PsiMethod method : methodsByName) {
114 final MethodSignature otherSignature = method.getSignature(PsiSubstitutor.EMPTY);
115 if (otherSignature.equals(patternSignature)) {
117 if (stopOnFirst) break;
121 return result.toArray(new PsiMethod[result.size()]);
124 final Set<HierarchicalMethodSignature> signatures = getOverrideEquivalentSignatures(aClass);
125 final HierarchicalMethodSignature signatureWithSupers = signatures.get(patternSignature);
126 if (signatureWithSupers == null) return PsiMethod.EMPTY_ARRAY;
127 final List<PsiMethod> result = new ArrayList<PsiMethod>();
128 MethodSignatureUtil.processMethodHierarchy(signatureWithSupers, new Processor<HierarchicalMethodSignature>() {
129 public boolean process(final HierarchicalMethodSignature sig) {
130 result.add(sig.getSignature().getMethod());
134 return result.toArray(new PsiMethod[result.size()]);
137 final PsiMethod
[] methodsByName
= aClass
.findMethodsByName(patternMethod
.getName(), checkBases
);
138 if (methodsByName
.length
== 0) return Collections
.emptyList();
139 final List
<PsiMethod
> methods
= new SmartList
<PsiMethod
>();
140 final MethodSignature patternSignature
= patternMethod
.getSignature(PsiSubstitutor
.EMPTY
);
141 for (final PsiMethod method
: methodsByName
) {
142 final PsiClass superClass
= method
.getContainingClass();
143 final PsiSubstitutor substitutor
;
144 if (checkBases
&& !aClass
.equals(superClass
)) {
145 substitutor
= TypeConversionUtil
.getSuperClassSubstitutor(superClass
, aClass
, PsiSubstitutor
.EMPTY
);
148 substitutor
= PsiSubstitutor
.EMPTY
;
150 final MethodSignature signature
= method
.getSignature(substitutor
);
151 if (signature
.equals(patternSignature
)) {
161 // ----------------------------------------------------------------------------------------
163 @Nullable public static PsiClass
findInnerByName(PsiClass aClass
, String name
, boolean checkBases
) {
164 final List
<PsiClass
> byMap
= findByMap(aClass
, name
, checkBases
, PsiClass
.class);
165 return byMap
.isEmpty() ?
null : byMap
.get(0);
168 @SuppressWarnings({"unchecked"})
169 @NotNull private static <T
extends PsiMember
> List
<T
> findByMap(PsiClass aClass
, String name
, boolean checkBases
, Class
<T
> type
) {
170 if (name
== null) return Collections
.emptyList();
174 if (ReflectionCache
.isAssignable(type
,PsiMethod
.class)) {
175 members
= (T
[])aClass
.getMethods();
177 else if (ReflectionCache
.isAssignable(type
,PsiClass
.class)) {
178 members
= (T
[])aClass
.getInnerClasses();
180 else if (ReflectionCache
.isAssignable(type
,PsiField
.class)) {
181 members
= (T
[])aClass
.getFields();
183 if (members
== null) return Collections
.emptyList();
185 List
<T
> list
= new ArrayList
<T
>();
186 for (T member
: members
) {
187 if (name
.equals(member
.getName())) list
.add(member
);
192 final Map
<String
, List
<Pair
<T
, PsiSubstitutor
>>> allMethodsMap
= getMap(aClass
, type
);
193 final List
<Pair
<T
, PsiSubstitutor
>> list
= allMethodsMap
.get(name
);
194 if (list
== null) return Collections
.emptyList();
195 final List
<T
> ret
= new ArrayList
<T
>();
196 for (final Pair
<T
, PsiSubstitutor
> info
: list
) {
197 ret
.add(info
.getFirst());
204 public static <T
extends PsiMember
> List
<Pair
<T
, PsiSubstitutor
>> getAllWithSubstitutorsByMap(PsiClass aClass
, Class
<T
> type
) {
205 final Map
<String
, List
<Pair
<T
, PsiSubstitutor
>>> allMap
= getMap(aClass
, type
);
206 return allMap
.get(ALL
);
209 @NotNull private static <T
extends PsiMember
> List
<T
> getAllByMap(PsiClass aClass
, Class
<T
> type
) {
210 List
<Pair
<T
, PsiSubstitutor
>> pairs
= getAllWithSubstitutorsByMap(aClass
, type
);
212 assert pairs
!= null : "pairs should be already computed. Wrong allMap: " + getMap(aClass
, type
);
214 final List
<T
> ret
= new ArrayList
<T
>(pairs
.size());
215 for (final Pair
<T
, PsiSubstitutor
> pair
: pairs
) {
216 T t
= pair
.getFirst();
217 LOG
.assertTrue(t
!= null, aClass
);
223 @NonNls private static final String ALL
= "Intellij-IDEA-ALL";
225 private static Map
<Class
<?
extends PsiMember
>, Map
<String
, List
<Pair
<PsiMember
, PsiSubstitutor
>>>> buildAllMaps(final PsiClass psiClass
) {
226 final List
<Pair
<PsiMember
, PsiSubstitutor
>> classes
= new ArrayList
<Pair
<PsiMember
, PsiSubstitutor
>>();
227 final List
<Pair
<PsiMember
, PsiSubstitutor
>> fields
= new ArrayList
<Pair
<PsiMember
, PsiSubstitutor
>>();
228 final List
<Pair
<PsiMember
, PsiSubstitutor
>> methods
= new ArrayList
<Pair
<PsiMember
, PsiSubstitutor
>>();
230 FilterScopeProcessor
<MethodCandidateInfo
> processor
= new FilterScopeProcessor
<MethodCandidateInfo
>(
231 new OrFilter(ElementClassFilter
.METHOD
, ElementClassFilter
.FIELD
, ElementClassFilter
.CLASS
)) {
232 protected void add(PsiElement element
, PsiSubstitutor substitutor
) {
233 if (element
instanceof PsiMethod
) {
234 methods
.add(new Pair
<PsiMember
, PsiSubstitutor
>((PsiMethod
)element
, substitutor
));
236 else if (element
instanceof PsiField
) {
237 fields
.add(new Pair
<PsiMember
, PsiSubstitutor
>((PsiField
)element
, substitutor
));
239 else if (element
instanceof PsiClass
) {
240 classes
.add(new Pair
<PsiMember
, PsiSubstitutor
>((PsiClass
)element
, substitutor
));
244 PsiElementFactory factory
= JavaPsiFacade
.getInstance(psiClass
.getProject()).getElementFactory();
245 processDeclarationsInClassNotCached(psiClass
, processor
, ResolveState
.initial(), new THashSet
<PsiClass
>(), null, psiClass
, false, factory
);
247 Map
<Class
<?
extends PsiMember
>, Map
<String
, List
<Pair
<PsiMember
, PsiSubstitutor
>>>> result
= new HashMap
<Class
<?
extends PsiMember
>, Map
<String
, List
<Pair
<PsiMember
, PsiSubstitutor
>>>>(3);
248 result
.put(PsiClass
.class, generateMapByList(classes
));
249 result
.put(PsiMethod
.class, generateMapByList(methods
));
250 result
.put(PsiField
.class, generateMapByList(fields
));
251 psiClass
.putUserData(NAME_MAPS_BUILT_FLAG
, Boolean
.TRUE
);
255 private static Map
<String
, List
<Pair
<PsiMember
, PsiSubstitutor
>>> generateMapByList(@NotNull final List
<Pair
<PsiMember
, PsiSubstitutor
>> list
) {
256 Map
<String
, List
<Pair
<PsiMember
, PsiSubstitutor
>>> map
= new HashMap
<String
, List
<Pair
<PsiMember
, PsiSubstitutor
>>>();
258 for (final Pair
<PsiMember
, PsiSubstitutor
> info
: list
) {
259 final PsiMember element
= info
.getFirst();
260 final String currentName
= element
.getName();
261 List
<Pair
<PsiMember
, PsiSubstitutor
>> listByName
= map
.get(currentName
);
262 if (listByName
== null) {
263 listByName
= new ArrayList
<Pair
<PsiMember
, PsiSubstitutor
>>(1);
264 map
.put(currentName
, listByName
);
266 listByName
.add(info
);
271 private static <T
extends PsiMember
> Map
<String
, List
<Pair
<T
, PsiSubstitutor
>>> getMap(final PsiClass aClass
, Class
<T
> memberClazz
) {
272 CachedValue
<Map
> value
= aClass
.getUserData(MAP_IN_CLASS_KEY
);
274 final CachedValueProvider
<Map
> provider
= new ByNameCachedValueProvider(aClass
);
275 value
= aClass
.getManager().getCachedValuesManager().createCachedValue(provider
, false);
276 //Do not cache for nonphysical elements
277 if (aClass
.isPhysical()) {
278 value
= ((UserDataHolderEx
)aClass
).putUserDataIfAbsent(MAP_IN_CLASS_KEY
, value
);
281 return (Map
<String
, List
<Pair
<T
, PsiSubstitutor
>>>)value
.getValue().get(memberClazz
);
284 private static class ClassIconRequest
{
285 public PsiClass psiClass
;
288 private ClassIconRequest(PsiClass psiClass
, int flags
) {
289 this.psiClass
= psiClass
;
294 public boolean equals(Object o
) {
295 if (this == o
) return true;
296 if (!(o
instanceof ClassIconRequest
)) return false;
298 ClassIconRequest that
= (ClassIconRequest
)o
;
300 if (flags
!= that
.flags
) return false;
301 if (psiClass
!= null ?
!psiClass
.equals(that
.psiClass
) : that
.psiClass
!= null) return false;
307 public int hashCode() {
308 int result
= psiClass
!= null ? psiClass
.hashCode() : 0;
309 result
= 31 * result
+ flags
;
314 private static final Function
<ClassIconRequest
, Icon
> FULL_ICON_EVALUATOR
= new Function
<ClassIconRequest
, Icon
>() {
315 public Icon
fun(ClassIconRequest r
) {
316 if (!r
.psiClass
.isValid() || r
.psiClass
.getProject().isDisposed()) return null;
318 final boolean isLocked
= (r
.flags
& Iconable
.ICON_FLAG_READ_STATUS
) != 0 && !r
.psiClass
.isWritable();
319 Icon symbolIcon
= ElementPresentationUtil
.getClassIconOfKind(r
.psiClass
, ElementPresentationUtil
.getClassKind(r
.psiClass
));
320 RowIcon baseIcon
= ElementBase
.createLayeredIcon(symbolIcon
, ElementPresentationUtil
.getFlags(r
.psiClass
, isLocked
));
321 return ElementPresentationUtil
.addVisibilityIcon(r
.psiClass
, r
.flags
, baseIcon
);
325 public static Icon
getClassIcon(final int flags
, final PsiClass aClass
) {
326 Icon symbolIcon
= ElementPresentationUtil
.getClassIconOfKind(aClass
, ElementPresentationUtil
.getBasicClassKind(aClass
));
327 RowIcon baseIcon
= ElementBase
.createLayeredIcon(symbolIcon
, 0);
329 return IconDeferrer
.getInstance().defer(ElementPresentationUtil
.addVisibilityIcon(aClass
, flags
, baseIcon
),
330 new ClassIconRequest(aClass
, flags
),
331 FULL_ICON_EVALUATOR
);
334 public static SearchScope
getClassUseScope(final PsiClass aClass
) {
335 final GlobalSearchScope maximalUseScope
= ((PsiManagerEx
) aClass
.getManager()).getFileManager().getUseScope(aClass
);
336 if (aClass
instanceof PsiAnonymousClass
) {
337 return new LocalSearchScope(aClass
);
339 PsiFile file
= aClass
.getContainingFile();
340 if (JspPsiUtil
.isInJspFile(file
)) return maximalUseScope
;
341 final PsiClass containingClass
= aClass
.getContainingClass();
342 if (aClass
.hasModifierProperty(PsiModifier
.PUBLIC
)) {
343 return containingClass
!= null ? containingClass
.getUseScope() : maximalUseScope
;
345 else if (aClass
.hasModifierProperty(PsiModifier
.PROTECTED
)) {
346 return containingClass
!= null ? containingClass
.getUseScope() : maximalUseScope
;
348 else if (aClass
.hasModifierProperty(PsiModifier
.PRIVATE
) || aClass
instanceof PsiTypeParameter
) {
349 PsiClass topClass
= PsiUtil
.getTopLevelClass(aClass
);
350 return new LocalSearchScope(topClass
== null ? aClass
.getContainingFile() : topClass
);
353 PsiPackage aPackage
= null;
354 if (file
instanceof PsiJavaFile
) {
355 aPackage
= JavaPsiFacade
.getInstance(aClass
.getProject()).findPackage(((PsiJavaFile
)file
).getPackageName());
358 if (aPackage
== null) {
359 PsiDirectory dir
= file
.getContainingDirectory();
361 aPackage
= JavaDirectoryService
.getInstance().getPackage(dir
);
365 if (aPackage
!= null) {
366 SearchScope scope
= PackageScope
.packageScope(aPackage
, false);
367 scope
= scope
.intersectWith(maximalUseScope
);
371 return new LocalSearchScope(file
);
375 public static boolean isMainMethod(PsiMethod method
) {
376 if (!PsiType
.VOID
.equals(method
.getReturnType())) return false;
377 PsiElementFactory factory
= JavaPsiFacade
.getInstance(method
.getProject()).getElementFactory();
379 PsiMethod appMain
= factory
.createMethodFromText("void main(String[] args);", null);
380 if (MethodSignatureUtil
.areSignaturesEqual(method
, appMain
)) return true;
381 PsiMethod appPremain
= factory
.createMethodFromText("void premain(String args, java.lang.instrument.Instrumentation i);", null);
382 if (MethodSignatureUtil
.areSignaturesEqual(method
, appPremain
)) return true;
384 catch (IncorrectOperationException e
) {
390 private static class ByNameCachedValueProvider
implements CachedValueProvider
<Map
> {
391 private final PsiClass myClass
;
393 private ByNameCachedValueProvider(final PsiClass aClass
) {
397 public Result
<Map
> compute() {
398 final Map
<Class
<?
extends PsiMember
>, Map
<String
, List
<Pair
<PsiMember
, PsiSubstitutor
>>>> map
= buildAllMaps(myClass
);
399 return new Result
<Map
>(map
, PsiModificationTracker
.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT
);
403 public static boolean processDeclarationsInClass(PsiClass aClass
,
404 PsiScopeProcessor processor
,
406 Set
<PsiClass
> visited
,
410 if (visited
!= null && visited
.contains(aClass
)) return true;
411 PsiSubstitutor substitutor
= state
.get(PsiSubstitutor
.KEY
);
412 isRaw
= isRaw
|| PsiUtil
.isRawSubstitutor(aClass
, substitutor
);
413 if (last
instanceof PsiTypeParameterList
|| last
instanceof PsiModifierList
) return true; //TypeParameterList and ModifierList do not see our declarations
414 final Boolean built
= aClass
.getUserData(NAME_MAPS_BUILT_FLAG
);
415 PsiElementFactory factory
= JavaPsiFacade
.getInstance(aClass
.getProject()).getElementFactory();
417 return processDeclarationsInClassNotCached(aClass
, processor
, state
, visited
, last
, place
, isRaw
, factory
);
420 final NameHint nameHint
= processor
.getHint(NameHint
.KEY
);
421 final ElementClassHint classHint
= processor
.getHint(ElementClassHint
.KEY
);
423 if (nameHint
!= null) {
424 if (classHint
== null || classHint
.shouldProcess(ElementClassHint
.DeclaractionKind
.FIELD
)) {
425 final PsiField fieldByName
= aClass
.findFieldByName(nameHint
.getName(state
), false);
426 if (fieldByName
!= null) {
427 processor
.handleEvent(PsiScopeProcessor
.Event
.SET_DECLARATION_HOLDER
, aClass
);
428 if (!processor
.execute(fieldByName
, state
)) return false;
431 final Map
<String
, List
<Pair
<PsiField
, PsiSubstitutor
>>> allFieldsMap
= getMap(aClass
, PsiField
.class);
433 final List
<Pair
<PsiField
, PsiSubstitutor
>> list
= allFieldsMap
.get(nameHint
.getName(state
));
435 for (final Pair
<PsiField
, PsiSubstitutor
> candidate
: list
) {
436 PsiField candidateField
= candidate
.getFirst();
437 PsiSubstitutor finalSubstitutor
= obtainFinalSubstitutor(candidateField
.getContainingClass(), candidate
.getSecond(), aClass
,
438 substitutor
, place
, factory
);
440 processor
.handleEvent(PsiScopeProcessor
.Event
.SET_DECLARATION_HOLDER
, candidateField
.getContainingClass());
441 if (!processor
.execute(candidateField
, state
.put(PsiSubstitutor
.KEY
, finalSubstitutor
))) return false;
446 if (classHint
== null || classHint
.shouldProcess(ElementClassHint
.DeclaractionKind
.CLASS
)) {
447 if (last
!= null && last
.getParent() == aClass
) {
448 if (last
instanceof PsiClass
) {
449 if (!processor
.execute(last
, state
)) return false;
452 final PsiTypeParameterList list
= aClass
.getTypeParameterList();
453 if (list
!= null && !list
.processDeclarations(processor
, state
, last
, place
)) return false;
455 if (!(last
instanceof PsiReferenceList
)) {
456 final PsiClass classByName
= aClass
.findInnerClassByName(nameHint
.getName(state
), false);
457 if (classByName
!= null) {
458 processor
.handleEvent(PsiScopeProcessor
.Event
.SET_DECLARATION_HOLDER
, aClass
);
459 if (!processor
.execute(classByName
, state
)) return false;
462 final Map
<String
, List
<Pair
<PsiClass
, PsiSubstitutor
>>> allClassesMap
= getMap(aClass
, PsiClass
.class);
464 final List
<Pair
<PsiClass
, PsiSubstitutor
>> list
= allClassesMap
.get(nameHint
.getName(state
));
466 for (final Pair
<PsiClass
, PsiSubstitutor
> candidate
: list
) {
467 final PsiClass inner
= candidate
.getFirst();
468 final PsiClass containingClass
= inner
.getContainingClass();
469 if (containingClass
!= null) {
470 PsiSubstitutor finalSubstitutor
= obtainFinalSubstitutor(containingClass
, candidate
.getSecond(), aClass
,
471 substitutor
, place
, factory
);
472 processor
.handleEvent(PsiScopeProcessor
.Event
.SET_DECLARATION_HOLDER
, containingClass
);
473 if (!processor
.execute(inner
, state
.put(PsiSubstitutor
.KEY
, finalSubstitutor
))) return false;
480 if (classHint
== null || classHint
.shouldProcess(ElementClassHint
.DeclaractionKind
.METHOD
)) {
481 if (processor
instanceof MethodResolverProcessor
) {
482 final MethodResolverProcessor methodResolverProcessor
= (MethodResolverProcessor
)processor
;
483 if (methodResolverProcessor
.isConstructor()) {
484 final PsiMethod
[] constructors
= aClass
.getConstructors();
485 methodResolverProcessor
.handleEvent(PsiScopeProcessor
.Event
.SET_DECLARATION_HOLDER
, aClass
);
486 for (PsiMethod constructor
: constructors
) {
487 if (!methodResolverProcessor
.execute(constructor
, state
)) return false;
492 final Map
<String
, List
<Pair
<PsiMethod
, PsiSubstitutor
>>> allMethodsMap
= getMap(aClass
, PsiMethod
.class);
493 final List
<Pair
<PsiMethod
, PsiSubstitutor
>> list
= allMethodsMap
.get(nameHint
.getName(state
));
495 for (final Pair
<PsiMethod
, PsiSubstitutor
> candidate
: list
) {
496 PsiMethod candidateMethod
= candidate
.getFirst();
497 if (processor
instanceof MethodResolverProcessor
) {
498 if (candidateMethod
.isConstructor() != ((MethodResolverProcessor
)processor
).isConstructor()) continue;
500 final PsiClass containingClass
= candidateMethod
.getContainingClass();
501 PsiSubstitutor finalSubstitutor
= obtainFinalSubstitutor(containingClass
, candidate
.getSecond(), aClass
,
502 substitutor
, place
, factory
);
503 if (isRaw
&& !candidateMethod
.hasModifierProperty(PsiModifier
.STATIC
)) { //static methods are not erased due to raw overriding
504 PsiTypeParameter
[] methodTypeParameters
= candidateMethod
.getTypeParameters();
505 finalSubstitutor
= factory
.createRawSubstitutor(finalSubstitutor
, methodTypeParameters
);
507 processor
.handleEvent(PsiScopeProcessor
.Event
.SET_DECLARATION_HOLDER
, containingClass
);
508 if (!processor
.execute(candidateMethod
, state
.put(PsiSubstitutor
.KEY
, finalSubstitutor
))) return false;
515 return processDeclarationsInClassNotCached(aClass
, processor
, state
, visited
, last
, place
, isRaw
, factory
);
518 private static PsiSubstitutor
obtainFinalSubstitutor(@NotNull PsiClass candidateClass
, PsiSubstitutor candidateSubstitutor
, PsiClass aClass
,
519 PsiSubstitutor substitutor
,
520 final PsiElement place
,
521 PsiElementFactory elementFactory
) {
522 if (PsiUtil
.isRawSubstitutor(aClass
, substitutor
)) {
523 return elementFactory
.createRawSubstitutor(candidateClass
);
526 final PsiType containingType
= elementFactory
.createType(candidateClass
, candidateSubstitutor
, PsiUtil
.getLanguageLevel(place
));
527 PsiType type
= substitutor
.substitute(containingType
);
528 if (!(type
instanceof PsiClassType
)) return candidateSubstitutor
;
529 return ((PsiClassType
)type
).resolveGenerics().getSubstitutor();
532 private static boolean processDeclarationsInClassNotCached(PsiClass aClass
, PsiScopeProcessor processor
, ResolveState state
, Set
<PsiClass
> visited
,
536 PsiElementFactory factory
) {
537 if (visited
== null) visited
= new THashSet
<PsiClass
>();
538 if (!visited
.add(aClass
)) return true;
539 processor
.handleEvent(PsiScopeProcessor
.Event
.SET_DECLARATION_HOLDER
, aClass
);
540 final ElementClassHint classHint
= processor
.getHint(ElementClassHint
.KEY
);
541 final NameHint nameHint
= processor
.getHint(NameHint
.KEY
);
544 if (classHint
== null || classHint
.shouldProcess(ElementClassHint
.DeclaractionKind
.FIELD
)) {
545 if (nameHint
!= null) {
546 final PsiField fieldByName
= aClass
.findFieldByName(nameHint
.getName(state
), false);
547 if (fieldByName
!= null) {
548 if (!processor
.execute(fieldByName
, state
)) return false;
552 final PsiField
[] fields
= aClass
.getFields();
553 for (final PsiField field
: fields
) {
554 if (!processor
.execute(field
, state
)) return false;
559 if (classHint
== null || classHint
.shouldProcess(ElementClassHint
.DeclaractionKind
.METHOD
)) {
560 final PsiMethod
[] methods
= nameHint
!= null ? aClass
.findMethodsByName(nameHint
.getName(state
), false) : aClass
.getMethods();
561 for (final PsiMethod method
: methods
) {
562 if (isRaw
&& !method
.hasModifierProperty(PsiModifier
.STATIC
)) { //static methods are not erased due to raw overriding
563 PsiTypeParameter
[] methodTypeParameters
= method
.getTypeParameters();
564 PsiSubstitutor raw
= factory
.createRawSubstitutor(state
.get(PsiSubstitutor
.KEY
), methodTypeParameters
);
565 state
= state
.put(PsiSubstitutor
.KEY
, raw
);
567 if (!processor
.execute(method
, state
)) return false;
571 if (classHint
== null || classHint
.shouldProcess(ElementClassHint
.DeclaractionKind
.CLASS
)) {
572 if (last
!= null && last
.getParent() == aClass
) {
574 final PsiTypeParameterList list
= aClass
.getTypeParameterList();
575 if (list
!= null && !list
.processDeclarations(processor
, ResolveState
.initial(), last
, place
)) return false;
578 if (!(last
instanceof PsiReferenceList
) && !(last
instanceof PsiModifierList
)) {
580 if (nameHint
!= null) {
581 final PsiClass inner
= aClass
.findInnerClassByName(nameHint
.getName(state
), false);
583 if (!processor
.execute(inner
, state
)) return false;
587 final PsiClass
[] inners
= aClass
.getInnerClasses();
588 for (final PsiClass inner
: inners
) {
589 if (!processor
.execute(inner
, state
)) return false;
595 return last
instanceof PsiReferenceList
|| processSuperTypes(aClass
, processor
, visited
, last
, place
, state
, isRaw
, factory
);
598 private static boolean processSuperTypes(PsiClass aClass
,
599 PsiScopeProcessor processor
,
600 Set
<PsiClass
> visited
,
604 boolean isRaw
, PsiElementFactory factory
) {
605 for (final PsiClassType superType
: aClass
.getSuperTypes()) {
606 final PsiClassType
.ClassResolveResult superTypeResolveResult
= superType
.resolveGenerics();
607 PsiClass superClass
= superTypeResolveResult
.getElement();
608 if (superClass
== null) continue;
609 PsiSubstitutor finalSubstitutor
= obtainFinalSubstitutor(superClass
, superTypeResolveResult
.getSubstitutor(), aClass
, state
.get(PsiSubstitutor
.KEY
),
611 if (!processDeclarationsInClass(superClass
, processor
, state
.put(PsiSubstitutor
.KEY
, finalSubstitutor
), visited
, last
, place
, isRaw
)) {
619 public static PsiClass
getSuperClass(PsiClass psiClass
) {
620 PsiManager manager
= psiClass
.getManager();
621 GlobalSearchScope resolveScope
= psiClass
.getResolveScope();
623 final JavaPsiFacade facade
= JavaPsiFacade
.getInstance(manager
.getProject());
624 if (psiClass
.isInterface()) {
625 return facade
.findClass(CommonClassNames
.JAVA_LANG_OBJECT
, resolveScope
);
627 if (psiClass
.isEnum()) {
628 return facade
.findClass(CommonClassNames
.JAVA_LANG_ENUM
, resolveScope
);
631 if (psiClass
instanceof PsiAnonymousClass
) {
632 PsiClassType baseClassReference
= ((PsiAnonymousClass
)psiClass
).getBaseClassType();
633 PsiClass baseClass
= baseClassReference
.resolve();
634 if (baseClass
== null || baseClass
.isInterface()) return facade
.findClass(CommonClassNames
.JAVA_LANG_OBJECT
, resolveScope
);
638 if (CommonClassNames
.JAVA_LANG_OBJECT
.equals(psiClass
.getQualifiedName())) return null;
640 final PsiClassType
[] referenceElements
= psiClass
.getExtendsListTypes();
642 if (referenceElements
.length
== 0) return facade
.findClass(CommonClassNames
.JAVA_LANG_OBJECT
, resolveScope
);
644 PsiClass psiResoved
= referenceElements
[0].resolve();
645 return psiResoved
== null ? facade
.findClass(CommonClassNames
.JAVA_LANG_OBJECT
, resolveScope
) : psiResoved
;
648 @NotNull public static PsiClass
[] getSupers(PsiClass psiClass
) {
649 final PsiClass
[] supers
= getSupersInner(psiClass
);
650 for (final PsiClass aSuper
: supers
) {
651 LOG
.assertTrue(aSuper
!= null);
656 private static PsiClass
[] getSupersInner(PsiClass psiClass
) {
657 PsiClassType
[] extendsListTypes
= psiClass
.getExtendsListTypes();
658 PsiClassType
[] implementsListTypes
= psiClass
.getImplementsListTypes();
660 if (psiClass
.isInterface()) {
661 return resolveClassReferenceList(extendsListTypes
,
662 psiClass
.getManager(), psiClass
.getResolveScope(), true);
665 if (psiClass
instanceof PsiAnonymousClass
) {
666 PsiAnonymousClass psiAnonymousClass
= (PsiAnonymousClass
)psiClass
;
667 PsiClassType baseClassReference
= psiAnonymousClass
.getBaseClassType();
668 PsiClass baseClass
= baseClassReference
.resolve();
669 if (baseClass
!= null) {
670 if (baseClass
.isInterface()) {
671 PsiClass objectClass
= JavaPsiFacade
.getInstance(psiClass
.getProject()).findClass("java.lang.Object", psiClass
.getResolveScope());
672 return objectClass
!= null ?
new PsiClass
[]{objectClass
, baseClass
} : new PsiClass
[]{baseClass
};
674 return new PsiClass
[]{baseClass
};
677 PsiClass objectClass
= JavaPsiFacade
.getInstance(psiClass
.getProject()).findClass("java.lang.Object", psiClass
.getResolveScope());
678 return objectClass
!= null ?
new PsiClass
[]{objectClass
} : PsiClass
.EMPTY_ARRAY
;
680 else if (psiClass
instanceof PsiTypeParameter
) {
681 if (extendsListTypes
.length
== 0) {
682 final PsiClass objectClass
=
683 JavaPsiFacade
.getInstance(psiClass
.getProject()).findClass("java.lang.Object", psiClass
.getResolveScope());
684 return objectClass
!= null ?
new PsiClass
[]{objectClass
} : PsiClass
.EMPTY_ARRAY
;
686 return resolveClassReferenceList(extendsListTypes
, psiClass
.getManager(),
687 psiClass
.getResolveScope(), false);
690 PsiClass
[] interfaces
= resolveClassReferenceList(implementsListTypes
, psiClass
.getManager(), psiClass
.getResolveScope(), false);
692 PsiClass superClass
= getSuperClass(psiClass
);
693 if (superClass
== null) return interfaces
;
694 PsiClass
[] types
= new PsiClass
[interfaces
.length
+ 1];
695 types
[0] = superClass
;
696 System
.arraycopy(interfaces
, 0, types
, 1, interfaces
.length
);
701 @NotNull public static PsiClassType
[] getSuperTypes(PsiClass psiClass
) {
702 if (psiClass
instanceof PsiAnonymousClass
) {
703 PsiClassType baseClassType
= ((PsiAnonymousClass
)psiClass
).getBaseClassType();
704 PsiClass baseClass
= baseClassType
.resolve();
705 if (baseClass
== null || !baseClass
.isInterface()) {
706 return new PsiClassType
[]{baseClassType
};
709 PsiClassType objectType
= PsiType
.getJavaLangObject(psiClass
.getManager(), psiClass
.getResolveScope());
710 return new PsiClassType
[]{objectType
, baseClassType
};
714 PsiClassType
[] extendsTypes
= psiClass
.getExtendsListTypes();
715 PsiClassType
[] implementsTypes
= psiClass
.getImplementsListTypes();
716 boolean hasExtends
= extendsTypes
.length
!= 0;
717 int extendsListLength
= extendsTypes
.length
+ (hasExtends ?
0 : 1);
718 PsiClassType
[] result
= new PsiClassType
[extendsListLength
+ implementsTypes
.length
];
720 System
.arraycopy(extendsTypes
, 0, result
, 0, extendsTypes
.length
);
722 if (CommonClassNames
.JAVA_LANG_OBJECT
.equals(psiClass
.getQualifiedName())) {
723 return PsiClassType
.EMPTY_ARRAY
;
725 PsiManager manager
= psiClass
.getManager();
726 PsiClassType objectType
= PsiType
.getJavaLangObject(manager
, psiClass
.getResolveScope());
727 result
[0] = objectType
;
729 System
.arraycopy(implementsTypes
, 0, result
, extendsListLength
, implementsTypes
.length
);
730 for (int i
= 0; i
< result
.length
; i
++) {
731 PsiClassType type
= result
[i
];
732 result
[i
] = (PsiClassType
)PsiUtil
.captureToplevelWildcards(type
, psiClass
);
737 private static PsiClassType
getAnnotationSuperType(PsiClass psiClass
, PsiElementFactory factory
) {
738 return factory
.createTypeByFQClassName("java.lang.annotation.Annotation", psiClass
.getResolveScope());
741 private static PsiClassType
getEnumSuperType(PsiClass psiClass
, PsiElementFactory factory
) {
742 PsiClassType superType
;
743 final PsiManager manager
= psiClass
.getManager();
744 final PsiClass enumClass
= JavaPsiFacade
.getInstance(manager
.getProject()).findClass("java.lang.Enum", psiClass
.getResolveScope());
745 if (enumClass
== null) {
747 superType
= (PsiClassType
)factory
.createTypeFromText("java.lang.Enum", null);
749 catch (IncorrectOperationException e
) {
754 final PsiTypeParameter
[] typeParameters
= enumClass
.getTypeParameters();
755 PsiSubstitutor substitutor
= PsiSubstitutor
.EMPTY
;
756 if (typeParameters
.length
== 1) {
757 substitutor
= substitutor
.put(typeParameters
[0], factory
.createType(psiClass
));
759 superType
= new PsiImmediateClassType(enumClass
, substitutor
);
764 public static PsiClass
[] getInterfaces(PsiTypeParameter typeParameter
) {
765 final ArrayList
<PsiClass
> result
= new ArrayList
<PsiClass
>();
766 final PsiClassType
[] referencedTypes
= typeParameter
.getExtendsListTypes();
767 for (PsiClassType referencedType
: referencedTypes
) {
768 final PsiClass psiClass
= referencedType
.resolve();
769 if (psiClass
!= null && psiClass
.isInterface()) {
770 result
.add(psiClass
);
773 return result
.toArray(new PsiClass
[result
.size()]);
776 public static PsiClass
[] getInterfaces(PsiClass psiClass
) {
777 final PsiClassType
[] extendsListTypes
= psiClass
.getExtendsListTypes();
778 if (psiClass
.isInterface()) {
779 return resolveClassReferenceList(extendsListTypes
, psiClass
.getManager(), psiClass
.getResolveScope(), false);
782 if (psiClass
instanceof PsiAnonymousClass
) {
783 PsiClassType baseClassReference
= ((PsiAnonymousClass
)psiClass
).getBaseClassType();
784 PsiClass baseClass
= baseClassReference
.resolve();
785 if (baseClass
!= null && baseClass
.isInterface()) return new PsiClass
[]{baseClass
};
786 return PsiClass
.EMPTY_ARRAY
;
789 final PsiClassType
[] implementsListTypes
= psiClass
.getImplementsListTypes();
791 return resolveClassReferenceList(implementsListTypes
, psiClass
.getManager(), psiClass
.getResolveScope(), false);
794 private static PsiClass
[] resolveClassReferenceList(final PsiClassType
[] listOfTypes
,
795 final PsiManager manager
, final GlobalSearchScope resolveScope
, boolean includeObject
)
797 PsiClass objectClass
= JavaPsiFacade
.getInstance(manager
.getProject()).findClass("java.lang.Object", resolveScope
);
798 if (objectClass
== null) includeObject
= false;
799 if (listOfTypes
== null || listOfTypes
.length
== 0) {
800 if (includeObject
) return new PsiClass
[]{objectClass
};
801 return PsiClass
.EMPTY_ARRAY
;
804 int referenceCount
= listOfTypes
.length
;
805 if (includeObject
) referenceCount
++;
807 PsiClass
[] resolved
= new PsiClass
[referenceCount
];
808 int resolvedCount
= 0;
810 if (includeObject
) resolved
[resolvedCount
++] = objectClass
;
811 for (PsiClassType reference
: listOfTypes
) {
812 PsiClass refResolved
= reference
.resolve();
813 if (refResolved
!= null) resolved
[resolvedCount
++] = refResolved
;
816 if (resolvedCount
< referenceCount
) {
817 PsiClass
[] shorter
= new PsiClass
[resolvedCount
];
818 System
.arraycopy(resolved
, 0, shorter
, 0, resolvedCount
);
825 public static List
<Pair
<PsiMethod
, PsiSubstitutor
>> findMethodsAndTheirSubstitutorsByName(PsiClass psiClass
, String name
, boolean checkBases
) {
827 final PsiMethod
[] methodsByName
= psiClass
.findMethodsByName(name
, false);
828 final List
<Pair
<PsiMethod
, PsiSubstitutor
>> ret
= new ArrayList
<Pair
<PsiMethod
, PsiSubstitutor
>>(methodsByName
.length
);
829 for (final PsiMethod method
: methodsByName
) {
830 ret
.add(new Pair
<PsiMethod
, PsiSubstitutor
>(method
, PsiSubstitutor
.EMPTY
));
834 final Map
<String
, List
<Pair
<PsiMethod
, PsiSubstitutor
>>> map
= getMap(psiClass
, PsiMethod
.class);
835 final List
<Pair
<PsiMethod
, PsiSubstitutor
>> list
= map
.get(name
);
836 return list
== null ?
837 Collections
.<Pair
<PsiMethod
, PsiSubstitutor
>>emptyList() :
838 Collections
.unmodifiableList(list
);
841 public static PsiClassType
[] getExtendsListTypes(PsiClass psiClass
) {
842 if (psiClass
.isEnum()) {
843 return new PsiClassType
[]{getEnumSuperType(psiClass
, JavaPsiFacade
.getInstance(psiClass
.getProject()).getElementFactory())};
845 else if (psiClass
.isAnnotationType()) {
846 return new PsiClassType
[]{getAnnotationSuperType(psiClass
, JavaPsiFacade
.getInstance(psiClass
.getProject()).getElementFactory())};
848 final PsiReferenceList extendsList
= psiClass
.getExtendsList();
849 if (extendsList
!= null) {
850 return extendsList
.getReferencedTypes();
852 return PsiClassType
.EMPTY_ARRAY
;
855 public static PsiClassType
[] getImplementsListTypes(PsiClass psiClass
) {
856 final PsiReferenceList extendsList
= psiClass
.getImplementsList();
857 if (extendsList
!= null) {
858 return extendsList
.getReferencedTypes();
860 return PsiClassType
.EMPTY_ARRAY
;
863 public static boolean isClassEquivalentTo(PsiClass aClass
, PsiElement another
) {
864 if (!(another
instanceof PsiClass
)) return false;
865 String name1
= aClass
.getName();
866 if (name1
== null) return false;
867 if (!another
.isValid()) return false;
868 String name2
= ((PsiClass
)another
).getName();
869 if (name2
== null) return false;
870 if (name1
.hashCode() != name2
.hashCode()) return false;
871 if (!name1
.equals(name2
)) return false;
872 String qName1
= aClass
.getQualifiedName();
873 String qName2
= ((PsiClass
)another
).getQualifiedName();
874 if (qName1
== null || qName2
== null) {
875 //noinspection StringEquality
876 if (qName1
!= qName2
) return false;
878 if (aClass
instanceof PsiTypeParameter
&& another
instanceof PsiTypeParameter
) {
879 PsiTypeParameter p1
= (PsiTypeParameter
)aClass
;
880 PsiTypeParameter p2
= (PsiTypeParameter
)another
;
882 return p1
.getIndex() == p2
.getIndex() &&
883 aClass
.getManager().areElementsEquivalent(p1
.getOwner(), p2
.getOwner());
890 if (qName1
.hashCode() != qName2
.hashCode() || !qName1
.equals(qName2
)) {
894 if (originalElement(aClass
).equals(originalElement((PsiClass
)another
))) {
898 final PsiFile file1
= aClass
.getContainingFile().getOriginalFile();
899 final PsiFile file2
= another
.getContainingFile().getOriginalFile();
900 if (file1
.equals(file2
)) {
904 //see com.intellij.openapi.vcs.changes.PsiChangeTracker
905 //see com.intellij.psi.impl.PsiFileFactoryImpl#createFileFromText(CharSequence,PsiFile)
906 final PsiFile original1
= file1
.getUserData(PsiFileFactory
.ORIGINAL_FILE
);
907 final PsiFile original2
= file2
.getUserData(PsiFileFactory
.ORIGINAL_FILE
);
908 if (original1
== original2
&& original1
!= null
909 || original1
== file2
|| original2
== file1
) {
913 final ProjectFileIndex fileIndex
= ProjectRootManager
.getInstance(aClass
.getProject()).getFileIndex();
914 final VirtualFile vfile1
= file1
.getViewProvider().getVirtualFile();
915 final VirtualFile vfile2
= file2
.getViewProvider().getVirtualFile();
916 return (fileIndex
.isInSource(vfile1
) || fileIndex
.isInLibraryClasses(vfile1
)) &&
917 (fileIndex
.isInSource(vfile2
) || fileIndex
.isInLibraryClasses(vfile2
));
920 private static PsiElement
originalElement(PsiClass aClass
) {
921 final PsiElement originalElement
= aClass
.getOriginalElement();
922 final PsiCompiledElement compiled
= originalElement
.getUserData(ClsElementImpl
.COMPILED_ELEMENT
);
923 if (compiled
!= null) {
926 return originalElement
;
929 public static boolean isFieldEquivalentTo(PsiField field
, PsiElement another
) {
930 if (!(another
instanceof PsiField
)) return false;
931 String name1
= field
.getName();
932 if (name1
== null) return false;
933 if (!another
.isValid()) return false;
935 String name2
= ((PsiField
)another
).getName();
936 if (!name1
.equals(name2
)) return false;
937 PsiClass aClass1
= field
.getContainingClass();
938 PsiClass aClass2
= ((PsiField
)another
).getContainingClass();
939 return aClass1
!= null && aClass2
!= null && field
.getManager().areElementsEquivalent(aClass1
, aClass2
);
942 public static boolean isMethodEquivalentTo(PsiMethod method1
, PsiElement another
) {
943 if (!(another
instanceof PsiMethod
)) return false;
944 PsiMethod method2
= (PsiMethod
)another
;
945 String name1
= method1
.getName();
946 if (!another
.isValid()) return false;
947 String name2
= method2
.getName();
948 if (!name1
.equals(name2
)) return false;
949 PsiClass aClass1
= method1
.getContainingClass();
950 PsiClass aClass2
= method2
.getContainingClass();
951 PsiManager manager
= method1
.getManager();
952 if (!(aClass1
!= null && aClass2
!= null && manager
.areElementsEquivalent(aClass1
, aClass2
))) return false;
954 PsiParameter
[] parameters1
= method1
.getParameterList().getParameters();
955 PsiParameter
[] parameters2
= method2
.getParameterList().getParameters();
956 if (parameters1
.length
!= parameters2
.length
) return false;
957 for (int i
= 0; i
< parameters1
.length
; i
++) {
958 PsiParameter parameter1
= parameters1
[i
];
959 PsiParameter parameter2
= parameters2
[i
];
960 PsiType type1
= parameter1
.getType();
961 PsiType type2
= parameter2
.getType();
962 if (!(type1
instanceof PsiClassType
) || !(type2
instanceof PsiClassType
)) {
963 if (!type1
.equals(type2
)) return false;
966 PsiClass class1
= ((PsiClassType
)type1
).resolve();
967 PsiClass class2
= ((PsiClassType
)type2
).resolve();
969 if (class1
instanceof PsiTypeParameter
&& class2
instanceof PsiTypeParameter
) {
970 return Comparing
.equal(class1
.getName(), class2
.getName()) &&
971 ((PsiTypeParameter
)class1
).getIndex() == ((PsiTypeParameter
)class2
).getIndex();
974 if (!manager
.areElementsEquivalent(class1
, class2
)) return false;