mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
check for duplicate methods made linear down from quadratic
This commit is contained in:
+29
-17
@@ -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();
|
||||
|
||||
+8
-10
@@ -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);
|
||||
|
||||
+30
-8
@@ -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);
|
||||
|
||||
+1
-1
@@ -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);
|
||||
}
|
||||
+1
-1
@@ -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>;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+20
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user