check for duplicate methods made linear down from quadratic

This commit is contained in:
Alexey Kudravtsev
2013-07-02 11:53:09 +04:00
parent 2250aa7f04
commit 7400c8f866
9 changed files with 141 additions and 78 deletions
@@ -38,8 +38,10 @@ import com.intellij.util.ArrayUtilRt;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.HashMap;
import com.intellij.util.containers.HashSet;
import com.intellij.util.containers.MostlySingularMultiMap;
import gnu.trove.THashMap;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
@@ -384,8 +386,11 @@ public class GenericsHighlightUtil {
}
@Nullable
public static HighlightInfo checkElementInTypeParameterExtendsList(PsiReferenceList referenceList, JavaResolveResult resolveResult, PsiElement element) {
PsiClass aClass = (PsiClass)referenceList.getParent();
public static HighlightInfo checkElementInTypeParameterExtendsList(@NotNull PsiReferenceList referenceList,
@NotNull PsiClass aClass,
@NotNull JavaResolveResult resolveResult,
@NotNull PsiElement element,
@NotNull MostlySingularMultiMap<MethodSignature, PsiMethod> duplicateMethods) {
final PsiJavaCodeReferenceElement[] referenceElements = referenceList.getReferenceElements();
PsiClass extendFrom = (PsiClass)resolveResult.getElement();
if (extendFrom == null) return null;
@@ -408,7 +413,7 @@ public class GenericsHighlightUtil {
if (errorResult == null && JavaVersionService.getInstance().isAtLeast(referenceList, JavaSdkVersion.JDK_1_7) &&
referenceElements.length > 1) {
//todo suppress erased methods which come from the same class
return checkOverrideEquivalentMethods(aClass);
return checkOverrideEquivalentMethods(aClass,duplicateMethods);
}
return errorResult;
}
@@ -462,14 +467,14 @@ public class GenericsHighlightUtil {
return null;
}
public static HighlightInfo checkOverrideEquivalentMethods(final PsiClass aClass) {
public static HighlightInfo checkOverrideEquivalentMethods(@NotNull PsiClass aClass, @NotNull MostlySingularMultiMap<MethodSignature, PsiMethod> duplicateMethods) {
final Collection<HierarchicalMethodSignature> signaturesWithSupers = aClass.getVisibleSignatures();
PsiManager manager = aClass.getManager();
Map<MethodSignature, MethodSignatureBackedByPsiMethod> sameErasureMethods =
new THashMap<MethodSignature, MethodSignatureBackedByPsiMethod>(MethodSignatureUtil.METHOD_PARAMETERS_ERASURE_EQUALITY);
for (HierarchicalMethodSignature signature : signaturesWithSupers) {
HighlightInfo info = checkSameErasureNotSubSignatureInner(signature, manager, aClass, sameErasureMethods);
HighlightInfo info = checkSameErasureNotSubSignatureInner(signature, manager, aClass, sameErasureMethods,duplicateMethods);
if (info != null) return info;
}
@@ -523,7 +528,8 @@ public class GenericsHighlightUtil {
private static HighlightInfo checkSameErasureNotSubSignatureInner(final HierarchicalMethodSignature signature,
final PsiManager manager,
final PsiClass aClass,
final Map<MethodSignature, MethodSignatureBackedByPsiMethod> sameErasureMethods) {
final Map<MethodSignature, MethodSignatureBackedByPsiMethod> sameErasureMethods,
@NotNull MostlySingularMultiMap<MethodSignature, PsiMethod> duplicateMethods) {
PsiMethod method = signature.getMethod();
JavaPsiFacade facade = JavaPsiFacade.getInstance(manager.getProject());
if (!facade.getResolveHelper().isAccessible(method, aClass, null)) return null;
@@ -535,7 +541,7 @@ public class GenericsHighlightUtil {
MethodSignatureUtil.findMethodBySuperMethod(aClass, sameErasure.getMethod(), false) != null ||
!(InheritanceUtil.isInheritorOrSelf(sameErasure.getMethod().getContainingClass(), method.getContainingClass(), true) ||
InheritanceUtil.isInheritorOrSelf(method.getContainingClass(), sameErasure.getMethod().getContainingClass(), true))) {
info = checkSameErasureNotSubSignatureOrSameClass(sameErasure, signature, aClass, method);
info = checkSameErasureNotSubSignatureOrSameClass(sameErasure, signature, aClass, method,duplicateMethods);
if (info != null) return info;
}
}
@@ -544,15 +550,18 @@ public class GenericsHighlightUtil {
}
List<HierarchicalMethodSignature> supers = signature.getSuperSignatures();
for (HierarchicalMethodSignature superSignature : supers) {
info = checkSameErasureNotSubSignatureInner(superSignature, manager, aClass, sameErasureMethods);
info = checkSameErasureNotSubSignatureInner(superSignature, manager, aClass, sameErasureMethods,duplicateMethods);
if (info != null) return info;
if (superSignature.isRaw() && !signature.isRaw()) {
final PsiType[] parameterTypes = signature.getParameterTypes();
PsiType[] types = superSignature.getParameterTypes();
for (int i = 0; i < types.length; i++) {
if (!Comparing.equal(parameterTypes[i], TypeConversionUtil.erasure(types[i]))) {
return getSameErasureMessage(false, method, superSignature.getMethod(), HighlightNamesUtil.getClassDeclarationTextRange(aClass));
PsiType[] erasedTypes = superSignature.getErasedParameterTypes();
for (int i = 0; i < erasedTypes.length; i++) {
if (!Comparing.equal(parameterTypes[i], erasedTypes[i])) {
//duplicateMethods.removeAllValues(signatureToErase);
//duplicateMethods.add(signatureToErase,method);
return getSameErasureMessage(false, method, superSignature.getMethod(),
HighlightNamesUtil.getClassDeclarationTextRange(aClass));
}
}
}
@@ -565,7 +574,8 @@ public class GenericsHighlightUtil {
private static HighlightInfo checkSameErasureNotSubSignatureOrSameClass(final MethodSignatureBackedByPsiMethod signatureToCheck,
final HierarchicalMethodSignature superSignature,
final PsiClass aClass,
final PsiMethod superMethod) {
final PsiMethod superMethod,
@NotNull MostlySingularMultiMap<MethodSignature, PsiMethod> duplicateMethods) {
final PsiMethod checkMethod = signatureToCheck.getMethod();
if (superMethod.equals(checkMethod)) return null;
PsiClass checkContainingClass = checkMethod.getContainingClass();
@@ -601,10 +611,10 @@ public class GenericsHighlightUtil {
!(checkEqualsSuper && Arrays.equals(superSignature.getParameterTypes(), signatureToCheck.getParameterTypes())) &&
!atLeast17) {
int idx = 0;
final PsiType[] parameterTypes = signatureToCheck.getParameterTypes();
boolean erasure = parameterTypes.length > 0;
final PsiType[] erasedTypes = signatureToCheck.getErasedParameterTypes();
boolean erasure = erasedTypes.length > 0;
for (PsiType type : superSignature.getParameterTypes()) {
erasure &= Comparing.equal(type, TypeConversionUtil.erasure(parameterTypes[idx]));
erasure &= Comparing.equal(type, erasedTypes[idx]);
idx++;
}
@@ -615,6 +625,8 @@ public class GenericsHighlightUtil {
return null;
}
if (superContainingClass != null && !superContainingClass.isInterface() && checkContainingClass.isInterface() && !aClass.equals(superContainingClass)) return null;
//duplicateMethods.removeAllValues(checkMethod.getSignature(PsiSubstitutor.EMPTY)); // do not highlight other methods
//duplicateMethods.add(checkMethod.getSignature(PsiSubstitutor.EMPTY),checkMethod);
if (aClass.equals(checkContainingClass)) {
boolean sameClass = aClass.equals(superContainingClass);
return getSameErasureMessage(sameClass, checkMethod, superMethod, HighlightNamesUtil.getMethodDeclarationTextRange(checkMethod));
@@ -1275,7 +1287,7 @@ public class GenericsHighlightUtil {
if (resolve instanceof PsiClass) {
final PsiClass containingClass = ((PsiClass)resolve).getContainingClass();
if (containingClass != null) {
if (psiClass.isInheritor(containingClass, true) ||
if (psiClass.isInheritor(containingClass, true) ||
unqualifiedNestedClassReferenceAccessedViaContainingClassInheritance(containingClass, ((PsiClass)resolve).getExtendsList()) ||
unqualifiedNestedClassReferenceAccessedViaContainingClassInheritance(containingClass, ((PsiClass)resolve).getImplementsList())) {
return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).descriptionAndTooltip(((PsiClass)resolve).getName() + " is not accessible in current context").range(ref).create();
@@ -35,6 +35,7 @@ import com.intellij.psi.infos.MethodCandidateInfo;
import com.intellij.psi.util.*;
import com.intellij.refactoring.util.RefactoringChangeUtil;
import com.intellij.ui.ColorUtil;
import com.intellij.util.containers.MostlySingularMultiMap;
import com.intellij.util.ui.UIUtil;
import com.intellij.xml.util.XmlStringUtil;
import org.intellij.lang.annotations.Language;
@@ -833,18 +834,15 @@ public class HighlightMethodUtil {
}
@Nullable
static HighlightInfo checkDuplicateMethod(PsiClass aClass, PsiMethod method) {
static HighlightInfo checkDuplicateMethod(PsiClass aClass,
@NotNull PsiMethod method,
@NotNull MostlySingularMultiMap<MethodSignature, PsiMethod> duplicateMethods) {
if (aClass == null || method instanceof ExternallyDefinedPsiElement) return null;
MethodSignature methodSignature = method.getSignature(PsiSubstitutor.EMPTY);
int methodCount = 0;
final PsiMethod[] methodsByName = aClass.findMethodsByName(method.getName(), false);
for (PsiMethod other : methodsByName) {
if (other instanceof ExternallyDefinedPsiElement) continue;
if (other == method ||
other.isConstructor() == method.isConstructor() && other.getSignature(PsiSubstitutor.EMPTY).equals(methodSignature)) {
methodCount++;
if (methodCount > 1) break;
}
int methodCount = 1;
List<PsiMethod> methods = (List<PsiMethod>)duplicateMethods.get(methodSignature);
if (methods.size() > 1) {
methodCount++;
}
if (methodCount == 1 && aClass.isEnum() &&
@@ -61,6 +61,7 @@ import com.intellij.util.ArrayUtilRt;
import com.intellij.util.Function;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.MostlySingularMultiMap;
import com.intellij.util.ui.UIUtil;
import com.intellij.xml.util.XmlStringUtil;
import gnu.trove.THashMap;
@@ -2508,7 +2509,8 @@ public class HighlightUtil extends HighlightUtilBase {
@Nullable
static HighlightInfo checkElementInReferenceList(@NotNull PsiJavaCodeReferenceElement ref,
@NotNull PsiReferenceList referenceList,
@NotNull JavaResolveResult resolveResult) {
@NotNull JavaResolveResult resolveResult,
@NotNull MostlySingularMultiMap<MethodSignature,PsiMethod> duplicateMethods) {
PsiElement resolved = resolveResult.getElement();
HighlightInfo highlightInfo = null;
PsiElement refGrandParent = referenceList.getParent();
@@ -2516,7 +2518,7 @@ public class HighlightUtil extends HighlightUtilBase {
PsiClass aClass = (PsiClass)resolved;
if (refGrandParent instanceof PsiClass) {
if (refGrandParent instanceof PsiTypeParameter) {
highlightInfo = GenericsHighlightUtil.checkElementInTypeParameterExtendsList(referenceList, resolveResult, ref);
highlightInfo = GenericsHighlightUtil.checkElementInTypeParameterExtendsList(referenceList, (PsiClass)refGrandParent, resolveResult, ref,duplicateMethods);
}
else {
highlightInfo = HighlightClassUtil.checkExtendsClassAndImplementsInterface(referenceList, resolveResult, ref);
@@ -39,11 +39,9 @@ import com.intellij.psi.impl.source.jsp.jspJava.JspClass;
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
import com.intellij.psi.javadoc.PsiDocComment;
import com.intellij.psi.javadoc.PsiDocTagValue;
import com.intellij.psi.util.MethodSignatureBackedByPsiMethod;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.TypeConversionUtil;
import com.intellij.psi.util.*;
import com.intellij.psi.xml.XmlAttributeValue;
import com.intellij.util.containers.MostlySingularMultiMap;
import gnu.trove.THashMap;
import gnu.trove.TObjectIntHashMap;
import org.jetbrains.annotations.NotNull;
@@ -82,11 +80,27 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
}
}
};
private final Map<PsiClass, MostlySingularMultiMap<MethodSignature, PsiMethod>> myDuplicateMethods = new THashMap<PsiClass, MostlySingularMultiMap<MethodSignature, PsiMethod>>();
public HighlightVisitorImpl(@NotNull PsiResolveHelper resolveHelper) {
myResolveHelper = resolveHelper;
}
@NotNull
private MostlySingularMultiMap<MethodSignature, PsiMethod> getDuplicateMethods(PsiClass aClass) {
MostlySingularMultiMap<MethodSignature, PsiMethod> signatures = myDuplicateMethods.get(aClass);
if (signatures == null) {
signatures = new MostlySingularMultiMap<MethodSignature, PsiMethod>();
for (PsiMethod method : aClass.getMethods()) {
MethodSignature signature = method.getSignature(PsiSubstitutor.EMPTY);
signatures.add(signature, method);
}
myDuplicateMethods.put(aClass, signatures);
}
return signatures;
}
@Override
@NotNull
public HighlightVisitorImpl clone() {
@@ -153,6 +167,7 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
myRefCountHolder = null;
myFile = null;
myHolder = null;
myDuplicateMethods.clear();
}
return success;
@@ -776,7 +791,7 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
}
PsiClass aClass = method.getContainingClass();
if (!myHolder.hasErrorResults()) myHolder.add(HighlightMethodUtil.checkMethodMustHaveBody(method, aClass));
if (!myHolder.hasErrorResults()) myHolder.add(HighlightMethodUtil.checkDuplicateMethod(aClass, method));
if (!myHolder.hasErrorResults()) myHolder.add(HighlightMethodUtil.checkDuplicateMethod(aClass, method, getDuplicateMethods(aClass)));
if (!myHolder.hasErrorResults()) myHolder.add(HighlightMethodUtil.checkConstructorCallsBaseClassConstructor(method, myRefCountHolder, myResolveHelper));
if (!myHolder.hasErrorResults()) myHolder.add(HighlightMethodUtil.checkStaticMethodOverride(method));
}
@@ -792,7 +807,7 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
myHolder.add(HighlightClassUtil.checkClassDoesNotCallSuperConstructorOrHandleExceptions(aClass, myRefCountHolder, myResolveHelper));
}
if (!myHolder.hasErrorResults()) myHolder.add(HighlightMethodUtil.checkOverrideEquivalentInheritedMethods(aClass));
if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkOverrideEquivalentMethods(aClass));
if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkOverrideEquivalentMethods(aClass,getDuplicateMethods(aClass)));
if (!myHolder.hasErrorResults()) myHolder.add(HighlightClassUtil.checkCyclicInheritance(aClass));
}
catch (IndexNotReadyException ignored) {
@@ -933,11 +948,18 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkCannotPassInner(ref));
if (resolved != null && parent instanceof PsiReferenceList) {
if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkElementInReferenceList(ref, (PsiReferenceList)parent, result));
if (!myHolder.hasErrorResults()) {
PsiReferenceList referenceList = (PsiReferenceList)parent;
PsiElement refParent = referenceList.getParent();
MostlySingularMultiMap<MethodSignature, PsiMethod> duplicateMethods = refParent instanceof PsiClass ? getDuplicateMethods(
(PsiClass)refParent) : MostlySingularMultiMap.<MethodSignature, PsiMethod>emptyMap();
myHolder.add(HighlightUtil.checkElementInReferenceList(ref, referenceList, result, duplicateMethods));
}
}
if (parent instanceof PsiAnonymousClass && ref.equals(((PsiAnonymousClass)parent).getBaseClassReference())) {
myHolder.add(GenericsHighlightUtil.checkOverrideEquivalentMethods((PsiClass)parent));
myHolder.add(GenericsHighlightUtil.checkOverrideEquivalentMethods((PsiClass)parent, getDuplicateMethods((PsiClass)parent)));
}
if (resolved instanceof PsiVariable) {
@@ -41,9 +41,14 @@ public abstract class MethodSignatureBase implements MethodSignature {
myTypeParameters = typeParameters;
}
protected MethodSignatureBase(@NotNull PsiSubstitutor substitutor, PsiParameterList parameterList, @Nullable PsiTypeParameterList typeParameterList) {
protected MethodSignatureBase(@NotNull PsiSubstitutor substitutor,
@Nullable PsiParameterList parameterList,
@Nullable PsiTypeParameterList typeParameterList) {
mySubstitutor = substitutor;
if (parameterList != null) {
if (parameterList == null) {
myParameterTypes = PsiType.EMPTY_ARRAY;
}
else {
final PsiParameter[] parameters = parameterList.getParameters();
myParameterTypes = parameters.length == 0 ? PsiType.EMPTY_ARRAY : new PsiType[parameters.length];
for (int i = 0; i < parameters.length; i++) {
@@ -52,9 +57,6 @@ public abstract class MethodSignatureBase implements MethodSignature {
myParameterTypes[i] = substitutor.substitute(type);
}
}
else {
myParameterTypes = PsiType.EMPTY_ARRAY;
}
myTypeParameters = typeParameterList == null ? PsiTypeParameter.EMPTY_ARRAY : typeParameterList.getTypeParameters();
}
@@ -74,7 +76,7 @@ public abstract class MethodSignatureBase implements MethodSignature {
public PsiType[] getErasedParameterTypes() {
PsiType[] result = myErasedParameterTypes;
if (result == null) {
myErasedParameterTypes = result = MethodSignatureUtil.getErasedParameterTypes(this);
myErasedParameterTypes = result = MethodSignatureUtil.calcErasedParameterTypes(this);
}
return result;
}
@@ -54,19 +54,20 @@ public class MethodSignatureUtil {
@Override
public boolean equals(MethodSignature method1, MethodSignature method2) {
return areSignaturesEqualLightweight(method1, method2) && checkErasedParametersEqual(method1, method2);
return areSignaturesEqualLightweight(method1, method2) && areErasedParametersEqual(method1, method2);
}
};
private static boolean checkErasedParametersEqual(MethodSignature method1, MethodSignature method2) {
private static boolean areErasedParametersEqual(@NotNull MethodSignature method1, @NotNull MethodSignature method2) {
PsiType[] erased1 = method1 instanceof MethodSignatureBase
? ((MethodSignatureBase)method1).getErasedParameterTypes() : getErasedParameterTypes(method1);
PsiType[] erased2 = method2 instanceof MethodSignatureBase
? ((MethodSignatureBase)method2).getErasedParameterTypes() : getErasedParameterTypes(method2);
? ((MethodSignatureBase)method1).getErasedParameterTypes() : calcErasedParameterTypes(method1);
PsiType[] erased2 = method2 instanceof MethodSignatureBase
? ((MethodSignatureBase)method2).getErasedParameterTypes() : calcErasedParameterTypes(method2);
return Arrays.equals(erased1, erased2);
}
public static PsiType[] getErasedParameterTypes(MethodSignature signature) {
@NotNull
public static PsiType[] calcErasedParameterTypes(@NotNull MethodSignature signature) {
PsiType[] parameterTypes = signature.getParameterTypes();
if (parameterTypes.length == 0) return PsiType.EMPTY_ARRAY;
@@ -78,6 +79,7 @@ public class MethodSignatureUtil {
return erasedTypes;
}
@NotNull
public static MethodSignature createMethodSignature(@NonNls @NotNull String name,
@Nullable PsiParameterList parameterTypes,
@Nullable PsiTypeParameterList typeParameterList,
@@ -85,6 +87,7 @@ public class MethodSignatureUtil {
return createMethodSignature(name, parameterTypes, typeParameterList, substitutor, false);
}
@NotNull
public static MethodSignature createMethodSignature(@NonNls @NotNull String name,
@Nullable PsiParameterList parameterTypes,
@Nullable PsiTypeParameterList typeParameterList,
@@ -93,6 +96,7 @@ public class MethodSignatureUtil {
return new MethodSignatureHandMade(name, parameterTypes, typeParameterList, substitutor, isConstructor);
}
@NotNull
public static MethodSignature createMethodSignature(@NonNls @NotNull String name,
@NotNull PsiType[] parameterTypes,
@NotNull PsiTypeParameter[] typeParameterList,
@@ -100,6 +104,7 @@ public class MethodSignatureUtil {
return createMethodSignature(name, parameterTypes, typeParameterList, substitutor, false);
}
@NotNull
public static MethodSignature createMethodSignature(@NonNls @NotNull String name,
@NotNull PsiType[] parameterTypes,
@NotNull PsiTypeParameter[] typeParameterList,
@@ -108,22 +113,22 @@ public class MethodSignatureUtil {
return new MethodSignatureHandMade(name, parameterTypes, typeParameterList, substitutor, isConstructor);
}
public static boolean areSignaturesEqual(PsiMethod method1, PsiMethod method2) {
public static boolean areSignaturesEqual(@NotNull PsiMethod method1, @NotNull PsiMethod method2) {
return method1.getSignature(PsiSubstitutor.EMPTY).equals(method2.getSignature(PsiSubstitutor.EMPTY));
}
public static boolean areSignaturesEqual(MethodSignature method1, MethodSignature method2) {
public static boolean areSignaturesEqual(@NotNull MethodSignature method1, @NotNull MethodSignature method2) {
if (method2 == method1) return true;
if (!areSignaturesEqualLightweight(method1, method2)) return false;
PsiSubstitutor unifyingSubstitutor = getSuperMethodSignatureSubstitutor(method1, method2);
return checkSignaturesEqualInner(method1, method2, unifyingSubstitutor);
return checkSignaturesEqualInner(method1, method2, getSuperMethodSignatureSubstitutor(method1, method2))
|| checkSignaturesEqualInner(method2, method1, getSuperMethodSignatureSubstitutor(method2, method1));
}
private static boolean checkSignaturesEqualInner(final MethodSignature subSignature,
final MethodSignature superSignature,
private static boolean checkSignaturesEqualInner(@NotNull MethodSignature subSignature,
@NotNull MethodSignature superSignature,
final PsiSubstitutor unifyingSubstitutor) {
if (unifyingSubstitutor == null) return false;
if (!checkErasedParametersEqual(subSignature, superSignature)) return false;
if (!areErasedParametersEqual(subSignature, superSignature)) return false;
final PsiType[] subParameterTypes = subSignature.getParameterTypes();
final PsiType[] superParameterTypes = superSignature.getParameterTypes();
@@ -138,12 +143,12 @@ public class MethodSignatureUtil {
return true;
}
public static boolean areSignaturesEqualLightweight(final MethodSignature sig1, final MethodSignature sig2) {
public static boolean areSignaturesEqualLightweight(@NotNull MethodSignature sig1, @NotNull MethodSignature sig2) {
final boolean isConstructor1 = sig1.isConstructor();
final boolean isConstructor2 = sig2.isConstructor();
if (isConstructor1 != isConstructor2) return false;
if (!isConstructor1 && !isConstructor2 || !(sig1 instanceof HierarchicalMethodSignature || sig2 instanceof HierarchicalMethodSignature)) {
if (!isConstructor1 || !(sig1 instanceof HierarchicalMethodSignature || sig2 instanceof HierarchicalMethodSignature)) {
final String name1 = sig1.getName();
final String name2 = sig2.getName();
if (!name1.equals(name2)) return false;
@@ -164,7 +169,7 @@ public class MethodSignatureUtil {
return true;
}
public static boolean isSuperMethod(final PsiMethod superMethodCandidate, final PsiMethod derivedMethod) {
public static boolean isSuperMethod(@NotNull PsiMethod superMethodCandidate, @NotNull PsiMethod derivedMethod) {
PsiClass superClassCandidate = superMethodCandidate.getContainingClass();
PsiClass derivedClass = derivedMethod.getContainingClass();
if (derivedClass == null || superClassCandidate == null) return false;
@@ -179,16 +184,16 @@ public class MethodSignatureUtil {
@Nullable
public static PsiMethod findMethodInSuperClassBySignatureInDerived(@NotNull final PsiClass aClass,
@NotNull final PsiClass superClass,
final MethodSignature signature,
@NotNull MethodSignature signature,
final boolean checkDeep) {
PsiSubstitutor superSubstitutor = TypeConversionUtil.getSuperClassSubstitutor(superClass, aClass, PsiSubstitutor.EMPTY);
return doFindMethodInSuperClassBySignatureInDerived(superClass, superSubstitutor, signature, checkDeep);
}
@Nullable
private static PsiMethod doFindMethodInSuperClassBySignatureInDerived(final PsiClass superClass,
final PsiSubstitutor superSubstitutor,
final MethodSignature signature,
private static PsiMethod doFindMethodInSuperClassBySignatureInDerived(@NotNull PsiClass superClass,
@NotNull PsiSubstitutor superSubstitutor,
@NotNull MethodSignature signature,
final boolean checkDeep) {
final String name = signature.getName();
final PsiMethod[] methods = superClass.findMethodsByName(name, false);
@@ -210,12 +215,12 @@ public class MethodSignatureUtil {
}
@Nullable
public static PsiMethod findMethodBySignature(final PsiClass aClass, final PsiMethod pattenMethod, boolean checkBases) {
public static PsiMethod findMethodBySignature(@NotNull PsiClass aClass, @NotNull PsiMethod pattenMethod, boolean checkBases) {
return findMethodBySignature(aClass, pattenMethod.getSignature(PsiSubstitutor.EMPTY), checkBases);
}
@Nullable
public static PsiMethod findMethodBySignature(final PsiClass aClass, final MethodSignature methodSignature, boolean checkBases) {
public static PsiMethod findMethodBySignature(@NotNull PsiClass aClass, @NotNull MethodSignature methodSignature, boolean checkBases) {
String name = methodSignature.isConstructor() ? aClass.getName() : methodSignature.getName();
List<Pair<PsiMethod, PsiSubstitutor>> pairs = aClass.findMethodsAndTheirSubstitutorsByName(name, checkBases);
for (Pair<PsiMethod, PsiSubstitutor> pair : pairs) {
@@ -228,7 +233,7 @@ public class MethodSignatureUtil {
}
@Nullable
public static PsiMethod findMethodBySuperSignature(final PsiClass aClass, final MethodSignature methodSignature, final boolean checkBases) {
public static PsiMethod findMethodBySuperSignature(@NotNull PsiClass aClass, @NotNull MethodSignature methodSignature, final boolean checkBases) {
String name = methodSignature.isConstructor() ? aClass.getName() : methodSignature.getName();
List<Pair<PsiMethod, PsiSubstitutor>> pairs = aClass.findMethodsAndTheirSubstitutorsByName(name, checkBases);
for (Pair<PsiMethod, PsiSubstitutor> pair : pairs) {
@@ -241,7 +246,7 @@ public class MethodSignatureUtil {
}
@Nullable
public static PsiMethod findMethodBySuperMethod(final PsiClass aClass, final PsiMethod method, final boolean checkBases) {
public static PsiMethod findMethodBySuperMethod(@NotNull PsiClass aClass, @NotNull PsiMethod method, final boolean checkBases) {
List<Pair<PsiMethod, PsiSubstitutor>> pairs = aClass.findMethodsAndTheirSubstitutorsByName(method.getName(), checkBases);
for (Pair<PsiMethod, PsiSubstitutor> pair : pairs) {
PsiMethod candidate = pair.first;
@@ -258,22 +263,23 @@ public class MethodSignatureUtil {
return null;
}
public static boolean hasOverloads(PsiMethod method) {
public static boolean hasOverloads(@NotNull PsiMethod method) {
return getOverloads(method).length > 1;
}
public static PsiMethod[] getOverloads(PsiMethod method) {
@NotNull
public static PsiMethod[] getOverloads(@NotNull PsiMethod method) {
PsiClass aClass = method.getContainingClass();
if (aClass == null) return new PsiMethod[]{method};
return aClass.findMethodsByName(method.getName(), false);
}
public static boolean areParametersErasureEqual(PsiMethod method1, PsiMethod method2) {
public static boolean areParametersErasureEqual(@NotNull PsiMethod method1, @NotNull PsiMethod method2) {
if (method1.getParameterList().getParametersCount() != method2.getParameterList().getParametersCount()) return false;
return areSignaturesErasureEqual(method1.getSignature(PsiSubstitutor.EMPTY), method2.getSignature(PsiSubstitutor.EMPTY));
}
public static boolean areSignaturesErasureEqual(MethodSignature signature1, MethodSignature signature2) {
public static boolean areSignaturesErasureEqual(@NotNull MethodSignature signature1, @NotNull MethodSignature signature2) {
return METHOD_PARAMETERS_ERASURE_EQUALITY.equals(signature1, signature2);
}
@@ -283,7 +289,7 @@ public class MethodSignatureUtil {
* @return null if signatures do not match
*/
@Nullable
public static PsiSubstitutor getSuperMethodSignatureSubstitutor(MethodSignature methodSignature, MethodSignature superMethodSignature) {
public static PsiSubstitutor getSuperMethodSignatureSubstitutor(@NotNull MethodSignature methodSignature, @NotNull MethodSignature superMethodSignature) {
PsiSubstitutor result = getSuperMethodSignatureSubstitutorImpl(methodSignature, superMethodSignature);
if (result == null) return null;
@@ -313,7 +319,7 @@ public class MethodSignatureUtil {
}
@Nullable
private static PsiSubstitutor getSuperMethodSignatureSubstitutorImpl(MethodSignature methodSignature, MethodSignature superSignature) {
private static PsiSubstitutor getSuperMethodSignatureSubstitutorImpl(@NotNull MethodSignature methodSignature, @NotNull MethodSignature superSignature) {
// normalize generic method declarations: correlate type parameters
// todo: correlate type params by name?
PsiTypeParameter[] methodTypeParameters = methodSignature.getTypeParameters();
@@ -332,7 +338,8 @@ public class MethodSignatureUtil {
return result;
}
public static PsiSubstitutor combineSubstitutors(PsiSubstitutor substitutor1, PsiSubstitutor substitutor2) {
@NotNull
public static PsiSubstitutor combineSubstitutors(@NotNull PsiSubstitutor substitutor1, @NotNull PsiSubstitutor substitutor2) {
if (substitutor1 == PsiSubstitutor.EMPTY) return substitutor2;
Set<PsiTypeParameter> parameters1 = substitutor1.getSubstitutionMap().keySet();
final PsiTypeParameter[] typeParameters = parameters1.toArray(new PsiTypeParameter[parameters1.size()]);
@@ -353,7 +360,7 @@ public class MethodSignatureUtil {
}
@NotNull
public static PsiMethod[] convertMethodSignaturesToMethods(List<? extends MethodSignatureBackedByPsiMethod> sameNameMethodList) {
public static PsiMethod[] convertMethodSignaturesToMethods(@NotNull List<? extends MethodSignatureBackedByPsiMethod> sameNameMethodList) {
final PsiMethod[] methods = new PsiMethod[sameNameMethodList.size()];
for (int i = 0; i < sameNameMethodList.size(); i++) {
methods[i] = sameNameMethodList.get(i).getMethod();
@@ -361,7 +368,7 @@ public class MethodSignatureUtil {
return methods;
}
public static boolean isSubsignature(MethodSignature superSignature, MethodSignature subSignature) {
public static boolean isSubsignature(@NotNull MethodSignature superSignature, @NotNull MethodSignature subSignature) {
if (subSignature == superSignature) return true;
if (!areSignaturesEqualLightweight(superSignature, subSignature)) return false;
PsiSubstitutor unifyingSubstitutor = getSuperMethodSignatureSubstitutor(subSignature, superSignature);
@@ -3,5 +3,5 @@ import java.util.List;
interface A
{
<<error descr="'add(E)' in 'java.util.List' clashes with 'add(E)' in 'java.util.Collection'; both methods have same erasure, yet neither overrides the other"></error>T extends List<?> & Collection<? extends Cloneable>> void foo(T x);
<<error descr="'addAll(Collection<? extends E>)' in 'java.util.Collection' clashes with 'addAll(Collection<? extends E>)' in 'java.util.List'; both methods have same erasure, yet neither overrides the other"></error>T extends List<?> & Collection<? extends Cloneable>> void foo(T x);
}
@@ -70,7 +70,7 @@ class Test {
abstract class F<T extends Throwable> {
<error descr="'foo(F<?>)' is already defined in 'Test.F'">abstract void foo(F<?> y)</error>;
abstract void foo(F<? extends Throwable> y);
<error descr="'foo(F<? extends Throwable>)' is already defined in 'Test.F'">abstract void foo(F<? extends Throwable> y)</error>;
}
}
@@ -91,6 +91,10 @@ public class LightAdvHighlightingPerformanceTest extends LightDaemonAnalyzerTest
private List<HighlightInfo> doTest(final int maxMillis) throws Exception {
configureByFile(getFilePath(""));
return startTest(maxMillis);
}
private List<HighlightInfo> startTest(int maxMillis) {
PsiDocumentManager.getInstance(getProject()).commitAllDocuments();
getFile().getText(); //to load text
CodeInsightTestFixtureImpl.ensureIndexesUpToDate(getProject());
@@ -124,4 +128,20 @@ public class LightAdvHighlightingPerformanceTest extends LightDaemonAnalyzerTest
fail("Actual: " + errors.size());
}
}
public void testDuplicateMethods() throws Exception {
StringBuilder text = new StringBuilder("class X {\n");
int N = 1000;
for (int i=0;i<N;i++) {
text.append("public void visit(C" + i + " param) {}\n");
}
for (int i=0;i<N;i++) {
text.append("class C" + i + " {}\n");
}
text.append("}");
configureFromFileText("x.java", text.toString());
List<HighlightInfo> infos = startTest(Math.max(1000, 10000 - JobSchedulerImpl.CORES_COUNT * 1000));
assertEmpty(infos);
}
}