deprecation removed
[fedora-idea.git] / java / java-impl / src / com / intellij / psi / impl / PsiSuperMethodImplUtil.java
blob5e5c93a61088cbf94ce6d75322678f43f63f7cfd
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.impl;
18 import com.intellij.openapi.util.Key;
19 import com.intellij.openapi.util.UserDataHolderEx;
20 import com.intellij.psi.*;
21 import com.intellij.psi.impl.source.HierarchicalMethodSignatureImpl;
22 import com.intellij.psi.search.searches.DeepestSuperMethodsSearch;
23 import com.intellij.psi.search.searches.SuperMethodsSearch;
24 import com.intellij.psi.util.*;
25 import com.intellij.util.SmartList;
26 import gnu.trove.THashMap;
27 import gnu.trove.THashSet;
28 import gnu.trove.TObjectHashingStrategy;
29 import org.jetbrains.annotations.NotNull;
30 import org.jetbrains.annotations.Nullable;
32 import java.util.*;
34 public class PsiSuperMethodImplUtil {
35 private static final Key<CachedValue<Map<MethodSignature, HierarchicalMethodSignature>>> SIGNATURES_KEY = Key.create("MAP_KEY");
37 private PsiSuperMethodImplUtil() {
40 @NotNull
41 public static PsiMethod[] findSuperMethods(PsiMethod method) {
42 return findSuperMethods(method, null);
45 @NotNull
46 public static PsiMethod[] findSuperMethods(PsiMethod method, boolean checkAccess) {
47 if (!canHaveSuperMethod(method, checkAccess, false)) return PsiMethod.EMPTY_ARRAY;
48 return findSuperMethodsInternal(method, null);
51 @NotNull
52 public static PsiMethod[] findSuperMethods(PsiMethod method, PsiClass parentClass) {
53 if (!canHaveSuperMethod(method, true, false)) return PsiMethod.EMPTY_ARRAY;
54 return findSuperMethodsInternal(method, parentClass);
58 @NotNull
59 private static PsiMethod[] findSuperMethodsInternal(PsiMethod method, PsiClass parentClass) {
60 List<MethodSignatureBackedByPsiMethod> outputMethods = findSuperMethodSignatures(method, parentClass, false);
62 return MethodSignatureUtil.convertMethodSignaturesToMethods(outputMethods);
65 @NotNull
66 public static List<MethodSignatureBackedByPsiMethod> findSuperMethodSignaturesIncludingStatic(PsiMethod method,
67 boolean checkAccess) {
68 if (!canHaveSuperMethod(method, checkAccess, true)) return Collections.emptyList();
69 return findSuperMethodSignatures(method, null, true);
72 @NotNull
73 private static List<MethodSignatureBackedByPsiMethod> findSuperMethodSignatures(PsiMethod method,
74 PsiClass parentClass,
75 boolean allowStaticMethod) {
77 return new ArrayList<MethodSignatureBackedByPsiMethod>(SuperMethodsSearch.search(method, parentClass, true, allowStaticMethod).findAll());
80 private static boolean canHaveSuperMethod(PsiMethod method, boolean checkAccess, boolean allowStaticMethod) {
81 if (method.isConstructor()) return false;
82 if (!allowStaticMethod && method.hasModifierProperty(PsiModifier.STATIC)) return false;
83 if (checkAccess && method.hasModifierProperty(PsiModifier.PRIVATE)) return false;
84 PsiClass parentClass = method.getContainingClass();
85 return parentClass != null && !"java.lang.Object".equals(parentClass.getQualifiedName());
88 @Nullable
89 public static PsiMethod findDeepestSuperMethod(PsiMethod method) {
90 if (!canHaveSuperMethod(method, true, false)) return null;
91 return DeepestSuperMethodsSearch.search(method).findFirst();
94 public static PsiMethod[] findDeepestSuperMethods(PsiMethod method) {
95 if (!canHaveSuperMethod(method, true, false)) return PsiMethod.EMPTY_ARRAY;
96 Collection<PsiMethod> collection = DeepestSuperMethodsSearch.search(method).findAll();
97 return collection.toArray(new PsiMethod[collection.size()]);
100 private static Map<MethodSignature, HierarchicalMethodSignature> buildMethodHierarchy(PsiClass aClass,
101 PsiSubstitutor substitutor,
102 final boolean includePrivates,
103 final Set<PsiClass> visited,
104 boolean isInRawContext) {
105 Map<MethodSignature, HierarchicalMethodSignature> result = new LinkedHashMap<MethodSignature, HierarchicalMethodSignature>();
106 final Map<MethodSignature, List<PsiMethod>> sameParameterErasureMethods = new THashMap<MethodSignature, List<PsiMethod>>(MethodSignatureUtil.METHOD_PARAMETERS_ERASURE_EQUALITY);
108 Map<MethodSignature, HierarchicalMethodSignatureImpl> map = new THashMap<MethodSignature, HierarchicalMethodSignatureImpl>(new TObjectHashingStrategy<MethodSignature>() {
109 public int computeHashCode(MethodSignature signature) {
110 return MethodSignatureUtil.METHOD_PARAMETERS_ERASURE_EQUALITY.computeHashCode(signature);
113 public boolean equals(MethodSignature o1, MethodSignature o2) {
114 if (!MethodSignatureUtil.METHOD_PARAMETERS_ERASURE_EQUALITY.equals(o1, o2)) return false;
115 List<PsiMethod> list = sameParameterErasureMethods.get(o1);
116 boolean toCheckReturnType = list != null && list.size() > 1;
117 if (!toCheckReturnType) return true;
118 PsiType returnType1 = ((MethodSignatureBackedByPsiMethod)o1).getMethod().getReturnType();
119 PsiType returnType2 = ((MethodSignatureBackedByPsiMethod)o2).getMethod().getReturnType();
120 if (returnType1 == null && returnType2 == null) return true;
121 if (returnType1 == null || returnType2 == null) return false;
123 PsiType erasure1 = TypeConversionUtil.erasure(o1.getSubstitutor().substitute(returnType1));
124 PsiType erasure2 = TypeConversionUtil.erasure(o2.getSubstitutor().substitute(returnType2));
125 return erasure1.equals(erasure2);
129 for (PsiMethod method : aClass.getMethods()) {
130 if (!includePrivates && method.hasModifierProperty(PsiModifier.PRIVATE)) continue;
131 final MethodSignatureBackedByPsiMethod signature = MethodSignatureBackedByPsiMethod.create(method, substitutor, isInRawContext);
132 HierarchicalMethodSignatureImpl newH = new HierarchicalMethodSignatureImpl(signature);
134 List<PsiMethod> list = sameParameterErasureMethods.get(signature);
135 if (list == null) {
136 list = new SmartList<PsiMethod>();
137 sameParameterErasureMethods.put(signature, list);
139 list.add(method);
141 result.put(signature, newH);
142 map.put(signature, newH);
145 for (PsiClassType superType : aClass.getSuperTypes()) {
146 PsiClassType.ClassResolveResult superTypeResolveResult = superType.resolveGenerics();
147 PsiClass superClass = superTypeResolveResult.getElement();
148 if (superClass == null) continue;
149 if (!visited.add(superClass)) continue; // cyclic inheritance
150 final PsiSubstitutor superSubstitutor = superTypeResolveResult.getSubstitutor();
151 PsiSubstitutor finalSubstitutor = obtainFinalSubstitutor(superClass, superSubstitutor, substitutor);
153 final boolean isInRawContextSuper = (isInRawContext || PsiUtil.isRawSubstitutor(superClass, superSubstitutor)) && superClass.getTypeParameters().length != 0;
154 Map<MethodSignature, HierarchicalMethodSignature> superResult = buildMethodHierarchy(superClass, finalSubstitutor, false, visited, isInRawContextSuper);
155 visited.remove(superClass);
157 for (Map.Entry<MethodSignature, HierarchicalMethodSignature> entry : superResult.entrySet()) {
158 HierarchicalMethodSignature hierarchicalMethodSignature = entry.getValue();
159 if (!PsiUtil.isAccessible(hierarchicalMethodSignature.getMethod(), aClass, aClass)) continue;
160 MethodSignature superSignature = entry.getKey();
161 HierarchicalMethodSignatureImpl existing = map.get(superSignature);
162 if (existing == null) {
163 map.put(superSignature, copy(hierarchicalMethodSignature));
165 else if (isReturnTypeIsMoreSpecificThan(hierarchicalMethodSignature, existing) && isSuperMethod(aClass, hierarchicalMethodSignature, existing)) {
166 HierarchicalMethodSignatureImpl newSuper = copy(hierarchicalMethodSignature);
167 mergeSupers(newSuper, existing);
168 map.put(superSignature, newSuper);
170 else if (isSuperMethod(aClass, existing, hierarchicalMethodSignature)) {
171 mergeSupers(existing, hierarchicalMethodSignature);
173 // just drop an invalid method declaration there - to highlight accordingly
174 else if (!result.containsKey(superSignature)) {
175 result.put(superSignature, hierarchicalMethodSignature);
181 for (Map.Entry<MethodSignature, HierarchicalMethodSignatureImpl> entry : map.entrySet()) {
182 HierarchicalMethodSignatureImpl hierarchicalMethodSignature = entry.getValue();
183 MethodSignature methodSignature = entry.getKey();
184 if (result.get(methodSignature) == null && PsiUtil.isAccessible(hierarchicalMethodSignature.getMethod(), aClass, aClass)) {
185 result.put(methodSignature, hierarchicalMethodSignature);
189 return result;
192 private static boolean isReturnTypeIsMoreSpecificThan(@NotNull HierarchicalMethodSignature thisSig, @NotNull HierarchicalMethodSignature thatSig) {
193 PsiType thisRet = thisSig.getMethod().getReturnType();
194 PsiType thatRet = thatSig.getMethod().getReturnType();
195 return thatRet != null && thisRet != null && !thatRet.equals(thisRet) && TypeConversionUtil.isAssignable(thatRet, thisRet);
198 private static void mergeSupers(final HierarchicalMethodSignatureImpl existing, final HierarchicalMethodSignature superSignature) {
199 for (HierarchicalMethodSignature existingSuper : existing.getSuperSignatures()) {
200 if (existingSuper.getMethod() == superSignature.getMethod()) {
201 for (HierarchicalMethodSignature signature : superSignature.getSuperSignatures()) {
202 mergeSupers((HierarchicalMethodSignatureImpl)existingSuper, signature);
204 return;
207 if (existing.getMethod() == superSignature.getMethod()) {
208 List<HierarchicalMethodSignature> existingSupers = existing.getSuperSignatures();
209 for (HierarchicalMethodSignature supers : superSignature.getSuperSignatures()) {
210 if (!existingSupers.contains(supers)) existing.addSuperSignature(copy(supers));
213 else {
214 HierarchicalMethodSignatureImpl copy = copy(superSignature);
215 existing.addSuperSignature(copy);
219 private static boolean isSuperMethod(PsiClass aClass,
220 HierarchicalMethodSignature hierarchicalMethodSignature,
221 HierarchicalMethodSignature superSignatureHierarchical) {
222 PsiMethod superMethod = superSignatureHierarchical.getMethod();
223 PsiClass superClass = superMethod.getContainingClass();
224 PsiClass containingClass = hierarchicalMethodSignature.getMethod().getContainingClass();
225 return !superMethod.isConstructor()
226 && !aClass.equals(superClass)
227 && PsiUtil.isAccessible(superMethod, aClass, aClass)
228 && MethodSignatureUtil.isSubsignature(superSignatureHierarchical, hierarchicalMethodSignature)
229 && superClass != null
230 && (containingClass != null && containingClass.isInterface() == superClass.isInterface() || superClass.isInterface() || "java.lang.Object".equals(superClass.getQualifiedName()))
234 private static HierarchicalMethodSignatureImpl copy(HierarchicalMethodSignature hi) {
235 HierarchicalMethodSignatureImpl hierarchicalMethodSignature = new HierarchicalMethodSignatureImpl(hi);
236 for (HierarchicalMethodSignature his : hi.getSuperSignatures()) {
237 hierarchicalMethodSignature.addSuperSignature(copy(his));
239 return hierarchicalMethodSignature;
242 private static PsiSubstitutor obtainFinalSubstitutor(PsiClass superClass,
243 PsiSubstitutor superSubstitutor,
244 PsiSubstitutor derivedSubstitutor) {
245 Map<PsiTypeParameter, PsiType> map = null;
246 for (PsiTypeParameter typeParameter : PsiUtil.typeParametersIterable(superClass)) {
247 PsiType type = superSubstitutor.substitute(typeParameter);
248 final PsiType t = derivedSubstitutor.substitute(type);
249 if (map == null) {
250 map = new THashMap<PsiTypeParameter, PsiType>();
252 map.put(typeParameter, t);
255 return map == null ? PsiSubstitutor.EMPTY : JavaPsiFacade.getInstance(superClass.getProject()).getElementFactory().createSubstitutor(map);
258 public static Collection<HierarchicalMethodSignature> getVisibleSignatures(PsiClass aClass) {
259 Map<MethodSignature, HierarchicalMethodSignature> map = getSignaturesMap(aClass);
260 return map.values();
263 @NotNull public static HierarchicalMethodSignature getHierarchicalMethodSignature(PsiMethod method) {
264 PsiClass aClass = method.getContainingClass();
265 HierarchicalMethodSignature result = null;
266 if (aClass != null) {
267 result = getSignaturesMap(aClass).get(method.getSignature(PsiSubstitutor.EMPTY));
269 if (result == null) {
270 result = new HierarchicalMethodSignatureImpl((MethodSignatureBackedByPsiMethod)method.getSignature(PsiSubstitutor.EMPTY));
272 return result;
275 private static Map<MethodSignature, HierarchicalMethodSignature> getSignaturesMap(final PsiClass aClass) {
276 CachedValue<Map<MethodSignature, HierarchicalMethodSignature>> value = aClass.getUserData(SIGNATURES_KEY);
277 if (value == null) {
278 BySignaturesCachedValueProvider provider = new BySignaturesCachedValueProvider(aClass);
279 value = CachedValuesManager.getManager(aClass.getProject()).createCachedValue(provider, false);
280 //Do not cache for nonphysical elements
281 if (aClass.isPhysical()) {
282 UserDataHolderEx dataHolder = (UserDataHolderEx)aClass;
283 value = dataHolder.putUserDataIfAbsent(SIGNATURES_KEY, value);
287 return value.getValue();
290 private static class BySignaturesCachedValueProvider implements CachedValueProvider<Map<MethodSignature, HierarchicalMethodSignature>> {
291 private final PsiClass myClass;
293 private BySignaturesCachedValueProvider(final PsiClass aClass) {
294 myClass = aClass;
297 public Result<Map<MethodSignature, HierarchicalMethodSignature>> compute() {
298 Map<MethodSignature, HierarchicalMethodSignature> result = buildMethodHierarchy(myClass, PsiSubstitutor.EMPTY, true, new THashSet<PsiClass>(), false);
299 assert result != null;
302 return new Result<Map<MethodSignature, HierarchicalMethodSignature>>(result, PsiModificationTracker.JAVA_STRUCTURE_MODIFICATION_COUNT);