optimisation: getMaybeSuperClassSubstitutor() allows to avoid extra isInheritor() check

This commit is contained in:
Alexey Kudravtsev
2014-07-18 14:58:41 +04:00
parent 60d088ff99
commit 685fdb418a
3 changed files with 53 additions and 31 deletions
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2013 JetBrains s.r.o.
* Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,6 +18,7 @@ package com.intellij.psi.util;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.*;
import gnu.trove.THashSet;
import gnu.trove.TObjectHashingStrategy;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
@@ -173,9 +174,9 @@ public class MethodSignatureUtil {
PsiClass superClassCandidate = superMethodCandidate.getContainingClass();
PsiClass derivedClass = derivedMethod.getContainingClass();
if (derivedClass == null || superClassCandidate == null) return false;
if (!derivedClass.isInheritor(superClassCandidate, true)) return false;
final PsiSubstitutor superSubstitutor = TypeConversionUtil.getSuperClassSubstitutor(superClassCandidate, derivedClass,
PsiSubstitutor.EMPTY);
final PsiSubstitutor superSubstitutor = TypeConversionUtil.getMaybeSuperClassSubstitutor(superClassCandidate, derivedClass,
PsiSubstitutor.EMPTY, new THashSet<PsiClass>());
if (superSubstitutor == null) return false;
final MethodSignature superSignature = superMethodCandidate.getSignature(superSubstitutor);
final MethodSignature derivedSignature = derivedMethod.getSignature(PsiSubstitutor.EMPTY);
return isSubsignature(superSignature, derivedSignature);
@@ -285,9 +285,9 @@ public class TypeConversionUtil {
return checkSuperTypesWithDifferentTypeArguments(fromResult, toClass, manager, toResult.getSubstitutor(), null, languageLevel);
}
else {
if (!toClass.isInheritor(fromClass, true)) return false;
PsiSubstitutor toSubstitutor = getSuperClassSubstitutor(fromClass, toClass, toResult.getSubstitutor());
return areSameArgumentTypes(fromClass, fromResult.getSubstitutor(), toSubstitutor);
PsiSubstitutor toSubstitutor = getMaybeSuperClassSubstitutor(fromClass, toClass, toResult.getSubstitutor(),
new THashSet<PsiClass>());
return toSubstitutor != null && areSameArgumentTypes(fromClass, fromResult.getSubstitutor(), toSubstitutor);
}
}
else if (languageLevel.compareTo(LanguageLevel.JDK_1_5) < 0) {
@@ -356,10 +356,12 @@ public class TypeConversionUtil {
derivedSubstitutor = getSuperClassSubstitutor(derived, derived, derivedSubstitutor);
return areSameArgumentTypes(derived, baseResult.getSubstitutor(), derivedSubstitutor, 1);
}
else if (base.isInheritor(derived, true)) {
derivedSubstitutor = getSuperClassSubstitutor(derived, derived, derivedSubstitutor);
PsiSubstitutor baseSubstitutor = getSuperClassSubstitutor(derived, base, baseResult.getSubstitutor());
if (!areSameArgumentTypes(derived, baseSubstitutor, derivedSubstitutor)) return false;
else {
PsiSubstitutor baseSubstitutor = getMaybeSuperClassSubstitutor(derived, base, baseResult.getSubstitutor(), new THashSet<PsiClass>());
if (baseSubstitutor != null) {
derivedSubstitutor = getSuperClassSubstitutor(derived, derived, derivedSubstitutor);
if (!areSameArgumentTypes(derived, baseSubstitutor, derivedSubstitutor)) return false;
}
}
if (visited == null) visited = new THashSet<PsiClass>();
@@ -1028,8 +1030,7 @@ public class TypeConversionUtil {
}
return derivedSubstitutor;
}
if (!derivedClassCandidate.isInheritor(superClassCandidate, true)) return null;
return getSuperClassSubstitutor(superClassCandidate, derivedClassCandidate, derivedSubstitutor);
return getMaybeSuperClassSubstitutor(superClassCandidate, derivedClassCandidate, derivedSubstitutor, new THashSet<PsiClass>());
}
private static final Set<String> ourReportedSuperClassSubstitutorExceptions = new ConcurrentHashSet<String>();
@@ -1039,29 +1040,49 @@ public class TypeConversionUtil {
* values that they have in <code>derivedClass</code>, given that type parameters in
* <code>derivedClass</code> are bound by <code>derivedSubstitutor</code>.
* <code>superClass</code> must be a super class/interface of <code>derivedClass</code> (as in
* <code>InheritanceUtil.isInheritor(derivedClass, superClass, true)</code>
* <code>InheritanceUtil.isInheritorOrSelf(derivedClass, superClass, true)</code>
*
* @return substitutor (never returns <code>null</code>)
* @see PsiClass#isInheritor(PsiClass, boolean)
* @see InheritanceUtil#isInheritorOrSelf(com.intellij.psi.PsiClass, com.intellij.psi.PsiClass, boolean)
*/
@NotNull
public static PsiSubstitutor getSuperClassSubstitutor(@NotNull PsiClass superClass,
@NotNull PsiClass derivedClass,
@NotNull PsiSubstitutor derivedSubstitutor) {
if (!superClass.hasTypeParameters() && superClass.getContainingClass() == null) return PsiSubstitutor.EMPTY; //optimization
Set<PsiClass> visited = new THashSet<PsiClass>();
PsiSubstitutor substitutor = getMaybeSuperClassSubstitutor(superClass, derivedClass, derivedSubstitutor, visited);
if (substitutor == null) {
if (ourReportedSuperClassSubstitutorExceptions.add(derivedClass.getQualifiedName() + "/" + superClass.getQualifiedName())) {
reportHierarchyInconsistency(superClass, derivedClass, visited);
}
return PsiSubstitutor.EMPTY;
}
return substitutor;
}
// the same as getSuperClassSubstitutor() but can return null, which means that classes were not inheritors
@Nullable
public static PsiSubstitutor getMaybeSuperClassSubstitutor(@NotNull PsiClass superClass,
@NotNull PsiClass derivedClass,
@NotNull PsiSubstitutor derivedSubstitutor,
@NotNull Set<PsiClass> visited) {
if (!superClass.hasTypeParameters() && superClass.getContainingClass() == null) {
return InheritanceUtil.isInheritorOrSelf(derivedClass, superClass, true) ? PsiSubstitutor.EMPTY : null; //optimization
}
final PsiManager manager = superClass.getManager();
if (PsiUtil.isRawSubstitutor(derivedClass, derivedSubstitutor)) {
return JavaPsiFacade.getInstance(manager.getProject()).getElementFactory().createRawSubstitutor(superClass);
return InheritanceUtil.isInheritorOrSelf(derivedClass, superClass, true) ? JavaPsiFacade.getInstance(manager.getProject()).getElementFactory().createRawSubstitutor(superClass) : null;
}
final PsiClass objectClass = JavaPsiFacade.getInstance(manager.getProject()).findClass(CommonClassNames.JAVA_LANG_OBJECT, superClass.getResolveScope());
if (manager.areElementsEquivalent(superClass, objectClass)) {
if (CommonClassNames.JAVA_LANG_OBJECT_SHORT.equals(superClass.getName()) &&
manager.areElementsEquivalent(superClass, JavaPsiFacade.getInstance(manager.getProject()).findClass(CommonClassNames.JAVA_LANG_OBJECT, superClass.getResolveScope()))) {
return PsiSubstitutor.EMPTY;
}
PsiSubstitutor substitutor;
final Set<PsiClass> visited = new THashSet<PsiClass>();
if (derivedClass instanceof PsiAnonymousClass) {
final PsiClassType baseType = ((PsiAnonymousClass)derivedClass).getBaseClassType();
final JavaResolveResult result = baseType.resolveGenerics();
@@ -1072,12 +1093,6 @@ public class TypeConversionUtil {
else {
substitutor = getSuperClassSubstitutorInner(superClass, derivedClass, derivedSubstitutor, visited, manager);
}
if (substitutor == null) {
if (ourReportedSuperClassSubstitutorExceptions.add(derivedClass.getQualifiedName() + "/" + superClass.getQualifiedName())) {
reportHierarchyInconsistency(superClass, derivedClass, visited);
}
return PsiSubstitutor.EMPTY;
}
return substitutor;
}
@@ -316,7 +316,8 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{
// prefer derived class
signatures.put(signature, info);
} else {
}
else {
final PsiMethodCallExpression methodCallExpression = PsiTreeUtil.getParentOfType(myArgumentsList, PsiMethodCallExpression.class);
if (methodCallExpression != null) {
final PsiReferenceExpression expression = methodCallExpression.getMethodExpression();
@@ -324,14 +325,19 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{
PsiClass currentClass;
if (qualifierExpression != null) {
currentClass = PsiUtil.resolveClassInClassTypeOnly(qualifierExpression.getType());
} else {
}
else {
currentClass = PsiTreeUtil.getParentOfType(expression, PsiClass.class);
}
if (currentClass != null && InheritanceUtil.isInheritorOrSelf(currentClass, class1, true) && InheritanceUtil.isInheritorOrSelf(currentClass, existingClass, true)) {
final PsiSubstitutor eSubstitutor = TypeConversionUtil.getSuperClassSubstitutor(existingClass, currentClass, PsiSubstitutor.EMPTY);
final PsiSubstitutor cSubstitutor = TypeConversionUtil.getSuperClassSubstitutor(class1, currentClass, PsiSubstitutor.EMPTY);
if (MethodSignatureUtil.areSignaturesEqual(existingMethod.getSignature(eSubstitutor), method.getSignature(cSubstitutor))) {
if (currentClass != null) {
final PsiSubstitutor eSubstitutor = TypeConversionUtil.getMaybeSuperClassSubstitutor(existingClass, currentClass,
PsiSubstitutor.EMPTY,
new THashSet<PsiClass>());
final PsiSubstitutor cSubstitutor = TypeConversionUtil.getMaybeSuperClassSubstitutor(class1, currentClass, PsiSubstitutor.EMPTY,
new THashSet<PsiClass>());
if (eSubstitutor != null && cSubstitutor != null &&
MethodSignatureUtil.areSignaturesEqual(existingMethod.getSignature(eSubstitutor), method.getSignature(cSubstitutor))) {
final PsiType returnType = eSubstitutor.substitute(existingMethod.getReturnType());
final PsiType returnType1 = cSubstitutor.substitute(method.getReturnType());
if (returnType != null && returnType1 != null && !returnType1.equals(returnType)) {