IDEA-99520 Groovy: check overloading methods have the same raw signatures

This commit is contained in:
Max Medvedev
2013-04-23 15:41:55 +04:00
parent b0a9f0737b
commit 9e21bde743
4 changed files with 64 additions and 12 deletions
@@ -336,7 +336,7 @@ public class GroovyAnnotator extends GroovyElementVisitor {
}
checkTypeDefinition(myHolder, typeDefinition);
checkDuplicateMethod(typeDefinition.getMethods(), myHolder);
checkDuplicateMethod(typeDefinition, myHolder);
checkImplementedMethodsOfClass(myHolder, typeDefinition);
checkConstructors(myHolder, typeDefinition);
@@ -1279,7 +1279,7 @@ public class GroovyAnnotator extends GroovyElementVisitor {
public void visitFile(GroovyFileBase file) {
final PsiClass scriptClass = file.getScriptClass();
if (scriptClass != null) {
checkDuplicateMethod(scriptClass.getMethods(), myHolder);
checkDuplicateMethod(scriptClass, myHolder);
}
}
@@ -1758,8 +1758,8 @@ public class GroovyAnnotator extends GroovyElementVisitor {
}
}
private static void checkDuplicateMethod(PsiMethod[] methods, AnnotationHolder holder) {
MultiMap<MethodSignature, PsiMethod> map = GrClosureSignatureUtil.findMethodSignatures(methods);
private static void checkDuplicateMethod(PsiClass clazz, AnnotationHolder holder) {
MultiMap<MethodSignature, PsiMethod> map = GrClosureSignatureUtil.findRawMethodSignatures(clazz.getMethods(), clazz);
processMethodDuplicates(map, holder);
}
@@ -18,6 +18,7 @@ package org.jetbrains.plugins.groovy.lang.psi.impl.signatures;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.Trinity;
import com.intellij.psi.*;
import com.intellij.psi.impl.PsiSubstitutorImpl;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.InheritanceUtil;
import com.intellij.psi.util.MethodSignature;
@@ -770,14 +771,41 @@ public class GrClosureSignatureUtil {
return result;
}
public static MultiMap<MethodSignature, PsiMethod> findMethodSignatures(PsiMethod[] methods) {
MultiMap<MethodSignature, PsiMethod> map = new MultiMap<MethodSignature, PsiMethod>();
for (PsiMethod method : methods) {
final PsiMethod actual = method instanceof GrReflectedMethod ? ((GrReflectedMethod)method).getBaseMethod() : method;
map.putValue(method.getSignature(PsiSubstitutor.EMPTY), actual);
@NotNull
public static MultiMap<MethodSignature, PsiMethod> findRawMethodSignatures(@NotNull PsiMethod[] methods, @NotNull PsiClass clazz) {
Map<PsiTypeParameter, PsiType> initialMap = ContainerUtil.newHashMap();
for (PsiTypeParameter parameter : clazz.getTypeParameters()) {
initialMap.put(parameter, null);
}
return map;
final PsiSubstitutor initialSubstitutor = PsiSubstitutorImpl.createSubstitutor(initialMap);
MultiMap<MethodSignature, PsiMethod> result = new MultiMap<MethodSignature, PsiMethod>();
for (PsiMethod method : methods) {
final PsiMethod actual = method instanceof GrReflectedMethod ? ((GrReflectedMethod)method).getBaseMethod() : method;
PsiSubstitutor substitutor = calcRawSubstitutor(initialMap, initialSubstitutor, actual);
result.putValue(method.getSignature(substitutor), actual);
}
return result;
}
@NotNull
private static PsiSubstitutor calcRawSubstitutor(@NotNull Map<PsiTypeParameter, PsiType> initialMap,
@NotNull PsiSubstitutor initialSubstitutor,
@NotNull PsiMethod actual) {
if (actual.hasTypeParameters()) {
final HashMap<PsiTypeParameter, PsiType> map1 = ContainerUtil.newHashMap(initialMap);
for (PsiTypeParameter parameter : actual.getTypeParameters()) {
map1.put(parameter, null);
}
return PsiSubstitutorImpl.createSubstitutor(map1);
}
else {
return initialSubstitutor;
}
}
private static MethodSignature generateSignature(String name,
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
* Copyright 2000-2013 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.
@@ -109,7 +109,7 @@ public class GrMethodConflictUtil {
String newName = prototype.getName();
PsiMethod[] methods = clazz.findMethodsByName(newName, false);
MultiMap<MethodSignature, PsiMethod> signatures = GrClosureSignatureUtil.findMethodSignatures(methods);
MultiMap<MethodSignature, PsiMethod> signatures = GrClosureSignatureUtil.findRawMethodSignatures(methods, clazz);
for (MethodSignature prototypeSignature : prototypeSignatures) {
for (PsiMethod method : signatures.get(prototypeSignature)) {
if (method != refactoredMethod) {
@@ -1238,4 +1238,28 @@ def e
def f
''')
}
void testDuplicateMethodsWithGenerics() {
testHighlighting('''\
class A<T, E> {
<error descr="Method with signature foo(Object) is already defined in the class 'A'">def foo(T t)</error> {}
<error descr="Method with signature foo(Object) is already defined in the class 'A'">def foo(E e)</error> {}
}
class B {
<error descr="Method with signature foo(Object) is already defined in the class 'B'">def <T> void foo(T t)</error> {}
<error descr="Method with signature foo(Object) is already defined in the class 'B'">def <E> void foo(E e)</error> {}
}
class C<T, E> {
<error descr="Method with signature foo(Object) is already defined in the class 'C'">def foo(T t, T t2 = null)</error> {}
<error descr="Method with signature foo(Object) is already defined in the class 'C'">def foo(E e)</error> {}
}
class D<T, E> {
<error descr="Method with signature foo(Object, Object) is already defined in the class 'D'">def foo(T t, E e)</error> {}
<error descr="Method with signature foo(Object, Object) is already defined in the class 'D'">def foo(E t, T e)</error> {}
def foo(E t) {}
}''')
}
}