diff --git a/java/java-psi-api/src/com/intellij/psi/util/MethodSignatureUtil.java b/java/java-psi-api/src/com/intellij/psi/util/MethodSignatureUtil.java index 388da3b05ab9..58c9755830e5 100644 --- a/java/java-psi-api/src/com/intellij/psi/util/MethodSignatureUtil.java +++ b/java/java-psi-api/src/com/intellij/psi/util/MethodSignatureUtil.java @@ -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()); + if (superSubstitutor == null) return false; final MethodSignature superSignature = superMethodCandidate.getSignature(superSubstitutor); final MethodSignature derivedSignature = derivedMethod.getSignature(PsiSubstitutor.EMPTY); return isSubsignature(superSignature, derivedSignature); diff --git a/java/java-psi-api/src/com/intellij/psi/util/TypeConversionUtil.java b/java/java-psi-api/src/com/intellij/psi/util/TypeConversionUtil.java index a45c62c8d08e..41b41a849955 100644 --- a/java/java-psi-api/src/com/intellij/psi/util/TypeConversionUtil.java +++ b/java/java-psi-api/src/com/intellij/psi/util/TypeConversionUtil.java @@ -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()); + 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()); + if (baseSubstitutor != null) { + derivedSubstitutor = getSuperClassSubstitutor(derived, derived, derivedSubstitutor); + if (!areSameArgumentTypes(derived, baseSubstitutor, derivedSubstitutor)) return false; + } } if (visited == null) visited = new THashSet(); @@ -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()); } private static final Set ourReportedSuperClassSubstitutorExceptions = new ConcurrentHashSet(); @@ -1039,29 +1040,49 @@ public class TypeConversionUtil { * values that they have in derivedClass, given that type parameters in * derivedClass are bound by derivedSubstitutor. * superClass must be a super class/interface of derivedClass (as in - * InheritanceUtil.isInheritor(derivedClass, superClass, true) + * InheritanceUtil.isInheritorOrSelf(derivedClass, superClass, true) * * @return substitutor (never returns null) * @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 visited = new THashSet(); + 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 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 visited = new THashSet(); 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; } diff --git a/java/java-psi-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java b/java/java-psi-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java index f136c843aa87..d73216ded011 100644 --- a/java/java-psi-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java +++ b/java/java-psi-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java @@ -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()); + final PsiSubstitutor cSubstitutor = TypeConversionUtil.getMaybeSuperClassSubstitutor(class1, currentClass, PsiSubstitutor.EMPTY, + new THashSet()); + 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)) {