mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
improved searching of method duplicates
This commit is contained in:
@@ -335,3 +335,4 @@ property.name.expected=Property name expected
|
||||
add.method.body=Add method body
|
||||
wildcards.are.not.allowed.in.extends.list=A super type may not specify a wildcard type
|
||||
method.doesnot.override.super=Method does not override method from its superclass
|
||||
method.duplicate={0} is already defined
|
||||
|
||||
@@ -33,13 +33,13 @@ import com.intellij.psi.*;
|
||||
import com.intellij.psi.infos.CandidateInfo;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.search.searches.SuperMethodsSearch;
|
||||
import com.intellij.psi.util.MethodSignature;
|
||||
import com.intellij.psi.util.MethodSignatureBackedByPsiMethod;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
import gnu.trove.THashSet;
|
||||
import gnu.trove.TObjectHashingStrategy;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.plugins.groovy.GroovyBundle;
|
||||
@@ -49,7 +49,6 @@ import org.jetbrains.plugins.groovy.annotator.intentions.dynamic.DynamicProperty
|
||||
import org.jetbrains.plugins.groovy.codeInspection.GroovyImportsTracker;
|
||||
import org.jetbrains.plugins.groovy.config.GroovyConfigUtils;
|
||||
import org.jetbrains.plugins.groovy.highlighter.DefaultHighlighter;
|
||||
import org.jetbrains.plugins.groovy.intentions.utils.DuplicatesUtil;
|
||||
import org.jetbrains.plugins.groovy.lang.groovydoc.psi.api.*;
|
||||
import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes;
|
||||
import org.jetbrains.plugins.groovy.lang.lexer.TokenSets;
|
||||
@@ -83,6 +82,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.util.GrVariableDeclarationOwner
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.GrClosureType;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GroovyScriptClass;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.types.GrClosureSignatureUtil;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.util.GroovyPropertyUtils;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
|
||||
import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil;
|
||||
@@ -953,34 +953,33 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator {
|
||||
}
|
||||
|
||||
private static void checkDuplicateMethod(GrMethod[] methods, AnnotationHolder holder) {
|
||||
final Map<GrMethod, List<GrMethod>> map = DuplicatesUtil.factorDuplicates(methods, new TObjectHashingStrategy<GrMethod>() {
|
||||
public int computeHashCode(GrMethod method) {
|
||||
return method.getSignature(PsiSubstitutor.EMPTY).hashCode();
|
||||
}
|
||||
|
||||
public boolean equals(GrMethod method1, GrMethod method2) {
|
||||
return method1.getSignature(PsiSubstitutor.EMPTY).equals(method2.getSignature(PsiSubstitutor.EMPTY));
|
||||
}
|
||||
});
|
||||
Map<MethodSignature, List<GrMethod>> map = GrClosureSignatureUtil.findMethodSignatures(methods);
|
||||
processMethodDuplicates(map, holder);
|
||||
}
|
||||
|
||||
protected static void processMethodDuplicates(Map<GrMethod, List<GrMethod>> map, AnnotationHolder holder) {
|
||||
HashSet<GrMethod> duplicateMethodsWarning = new HashSet<GrMethod>();
|
||||
HashSet<GrMethod> duplicateMethodsErrors = new HashSet<GrMethod>();
|
||||
|
||||
DuplicatesUtil.collectMethodDuplicates(map, duplicateMethodsWarning, duplicateMethodsErrors);
|
||||
|
||||
for (GrMethod duplicateMethod : duplicateMethodsErrors) {
|
||||
holder.createErrorAnnotation(duplicateMethod.getNameIdentifierGroovy(),
|
||||
GroovyBundle.message("repetitive.method.name.signature.and.return.type"));
|
||||
}
|
||||
|
||||
for (GrMethod duplicateMethod : duplicateMethodsWarning) {
|
||||
holder.createWarningAnnotation(duplicateMethod.getNameIdentifierGroovy(), GroovyBundle.message("repetitive.method.name.signature"));
|
||||
protected static void processMethodDuplicates(Map<MethodSignature, List<GrMethod>> map, AnnotationHolder holder) {
|
||||
for (MethodSignature signature : map.keySet()) {
|
||||
List<GrMethod> methods = map.get(signature);
|
||||
if (methods.size() > 1) {
|
||||
String signaturePresentation = getSignaturePresentation(signature);
|
||||
for (GrMethod method : methods) {
|
||||
holder.createErrorAnnotation(method.getNameIdentifierGroovy(), GroovyBundle.message("method.duplicate", signaturePresentation));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static String getSignaturePresentation(MethodSignature signature) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append(signature.getName()).append('(');
|
||||
PsiType[] types = signature.getParameterTypes();
|
||||
for (PsiType type : types) {
|
||||
builder.append(type.getPresentableText()).append(", ");
|
||||
}
|
||||
if (types.length > 0) builder.delete(builder.length() - 2, builder.length());
|
||||
builder.append(")");
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private static void checkTypeDefinition(AnnotationHolder holder, GrTypeDefinition typeDefinition) {
|
||||
final GroovyConfigUtils configUtils = GroovyConfigUtils.getInstance();
|
||||
|
||||
+7
-9
@@ -328,18 +328,16 @@ public class GroovyParameterInfoHandler implements ParameterInfoHandler<GroovyPs
|
||||
if (parameters.length > 0) {
|
||||
for (int i = 0; i < parameters.length; i++) {
|
||||
if (i > 0) buffer.append(", ");
|
||||
final String name = parameters[i].getName();
|
||||
final PsiType psiType = parameters[i].getType();
|
||||
if (name == null) {
|
||||
buffer.append(psiType == null ? "null" : psiType.getPresentableText());
|
||||
if (psiType == null) {
|
||||
buffer.append("def");
|
||||
}
|
||||
else {
|
||||
String typeText = psiType == null ? "def" : psiType.getPresentableText();
|
||||
buffer.append(typeText).append(' ').append(name);
|
||||
final GrExpression initializer = parameters[i].getDefaultInitializer();
|
||||
if (initializer != null) {
|
||||
buffer.append(" = ").append(initializer.getText());
|
||||
}
|
||||
buffer.append(psiType.getPresentableText());
|
||||
}
|
||||
final GrExpression initializer = parameters[i].getDefaultInitializer();
|
||||
if (initializer != null) {
|
||||
buffer.append(" = ").append(initializer.getText());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-3
@@ -35,7 +35,4 @@ public interface GrClosureParameter {
|
||||
GrExpression getDefaultInitializer();
|
||||
|
||||
boolean isValid();
|
||||
|
||||
@Nullable
|
||||
String getName();
|
||||
}
|
||||
|
||||
+3
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package org.jetbrains.plugins.groovy.lang.psi.api.types;
|
||||
|
||||
import com.intellij.psi.PsiSubstitutor;
|
||||
import com.intellij.psi.PsiType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -23,6 +24,8 @@ import org.jetbrains.annotations.Nullable;
|
||||
* @author Maxim.Medvedev
|
||||
*/
|
||||
public interface GrClosureSignature {
|
||||
@NotNull PsiSubstitutor getSubstitutor();
|
||||
|
||||
@NotNull
|
||||
GrClosureParameter[] getParameters();
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrClosureParameter;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrClosureSignature;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.types.GrClosureSignatureUtil;
|
||||
|
||||
/**
|
||||
* @author ven
|
||||
|
||||
+2
-13
@@ -29,12 +29,10 @@ import org.jetbrains.plugins.groovy.lang.psi.api.types.GrClosureParameter;
|
||||
*/
|
||||
public class GrClosureParameterImpl implements GrClosureParameter {
|
||||
@Nullable final PsiType myType;
|
||||
@Nullable final String myName=null;
|
||||
final boolean myOptional;
|
||||
@Nullable final GrExpression myDefaultInitializer;
|
||||
|
||||
public GrClosureParameterImpl(/*String name,*/ PsiType type, boolean optional, GrExpression defaultInitializer) {
|
||||
// myName = name;
|
||||
public GrClosureParameterImpl(PsiType type, boolean optional, GrExpression defaultInitializer) {
|
||||
myType = type;
|
||||
myOptional = optional;
|
||||
if (myOptional) {
|
||||
@@ -45,16 +43,12 @@ public class GrClosureParameterImpl implements GrClosureParameter {
|
||||
}
|
||||
}
|
||||
|
||||
public GrClosureParameterImpl(@Nullable PsiType type) {
|
||||
this(/*null,*/ type, false, null);
|
||||
}
|
||||
|
||||
public GrClosureParameterImpl(PsiParameter parameter) {
|
||||
this(parameter, PsiSubstitutor.EMPTY);
|
||||
}
|
||||
|
||||
public GrClosureParameterImpl(PsiParameter parameter, PsiSubstitutor substitutor) {
|
||||
this(/*parameter.getName(), */substitutor.substitute(parameter.getType()),
|
||||
this(substitutor.substitute(parameter.getType()),
|
||||
parameter instanceof GrParameter ? ((GrParameter)parameter).isOptional() : false,
|
||||
parameter instanceof GrParameter ? ((GrParameter)parameter).getDefaultInitializer() : null);
|
||||
}
|
||||
@@ -78,11 +72,6 @@ public class GrClosureParameterImpl implements GrClosureParameter {
|
||||
return (myType == null || myType.isValid()) && (myDefaultInitializer == null || myDefaultInitializer.isValid());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getName() {
|
||||
return myName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof GrClosureParameter) {
|
||||
|
||||
+8
-5
@@ -32,6 +32,7 @@ public class GrClosureSignatureImpl implements GrClosureSignature {
|
||||
private final boolean myIsVarargs;
|
||||
@Nullable private final PsiType myReturnType;
|
||||
@NotNull private final GrClosureParameter[] myParameters;
|
||||
@NotNull private PsiSubstitutor mySubstitutor;
|
||||
|
||||
public GrClosureSignatureImpl(@NotNull PsiParameter[] parameters, @Nullable PsiType returnType, @NotNull PsiSubstitutor substitutor) {
|
||||
myReturnType = substitutor.substitute(returnType);
|
||||
@@ -46,16 +47,13 @@ public class GrClosureSignatureImpl implements GrClosureSignature {
|
||||
else {
|
||||
myIsVarargs = false;
|
||||
}
|
||||
mySubstitutor = substitutor;
|
||||
}
|
||||
|
||||
public GrClosureSignatureImpl(PsiParameter[] parameters, PsiType returnType) {
|
||||
this(parameters, returnType, PsiSubstitutor.EMPTY);
|
||||
}
|
||||
|
||||
public GrClosureSignatureImpl(PsiParameter[] parameters) {
|
||||
this(parameters, null);
|
||||
}
|
||||
|
||||
public GrClosureSignatureImpl(@NotNull GrClosableBlock block) {
|
||||
this(block.getAllParameters(), block.getReturnType());
|
||||
}
|
||||
@@ -68,7 +66,7 @@ public class GrClosureSignatureImpl implements GrClosureSignature {
|
||||
this(method.getParameterList().getParameters(), PsiUtil.getSmartReturnType(method), substitutor);
|
||||
}
|
||||
|
||||
private GrClosureSignatureImpl(@NotNull GrClosureParameter[] params, @Nullable PsiType returnType, boolean isVarArgs) {
|
||||
GrClosureSignatureImpl(@NotNull GrClosureParameter[] params, @Nullable PsiType returnType, boolean isVarArgs) {
|
||||
myParameters = params;
|
||||
myReturnType = returnType;
|
||||
myIsVarargs = isVarArgs;
|
||||
@@ -85,6 +83,11 @@ public class GrClosureSignatureImpl implements GrClosureSignature {
|
||||
return myReturnType;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public PsiSubstitutor getSubstitutor() {
|
||||
return mySubstitutor;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public GrClosureParameter[] getParameters() {
|
||||
GrClosureParameter[] result = new GrClosureParameter[myParameters.length];
|
||||
|
||||
+67
-7
@@ -13,25 +13,27 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jetbrains.plugins.groovy.lang.psi.impl;
|
||||
package org.jetbrains.plugins.groovy.lang.psi.impl.types;
|
||||
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.util.MethodSignature;
|
||||
import com.intellij.psi.util.MethodSignatureUtil;
|
||||
import gnu.trove.THashMap;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrNamedArgument;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrClosureParameter;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrClosureSignature;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.GrTupleType;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.types.GrClosureSignatureImpl;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author Maxim.Medvedev
|
||||
@@ -70,7 +72,7 @@ public class GrClosureSignatureUtil {
|
||||
}
|
||||
|
||||
private static boolean isApplicable(GrClosureSignature signature, PsiType[] args, PsiManager manager, GlobalSearchScope scope) {
|
||||
GrClosureParameter[] params = signature.getParameters();
|
||||
GrClosureParameter[] params = signature.getParameters();
|
||||
if (args.length > params.length && !signature.isVarargs()) return false;
|
||||
int optional = getOptionalParamCount(signature, false);
|
||||
int notOptional = params.length - optional;
|
||||
@@ -344,4 +346,62 @@ public class GrClosureSignatureUtil {
|
||||
return copy;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static List<MethodSignature> generateAllSignaturesForMethod(GrMethod method, PsiSubstitutor substitutor) {
|
||||
GrClosureSignature signature = createSignature(method, substitutor);
|
||||
String name = method.getName();
|
||||
GrClosureParameter[] params = signature.getParameters();
|
||||
PsiTypeParameter[] typeParameters = method.getTypeParameters();
|
||||
|
||||
ArrayList<PsiType> newParams = new ArrayList<PsiType>(params.length);
|
||||
ArrayList<GrClosureParameter> opts = new ArrayList<GrClosureParameter>(params.length);
|
||||
ArrayList<Integer> optInds = new ArrayList<Integer>(params.length);
|
||||
|
||||
for (int i = 0; i < params.length; i++) {
|
||||
if (params[i].isOptional()) {
|
||||
opts.add(params[i]);
|
||||
optInds.add(i);
|
||||
}
|
||||
else {
|
||||
newParams.add(params[i].getType());
|
||||
}
|
||||
}
|
||||
|
||||
List<MethodSignature> result = new ArrayList<MethodSignature>(opts.size() + 1);
|
||||
result.add(generateSignature(name, newParams, typeParameters, substitutor));
|
||||
for (int i = 0; i < opts.size(); i++) {
|
||||
newParams.add(optInds.get(i), opts.get(i).getType());
|
||||
result.add(generateSignature(name, newParams, typeParameters, substitutor));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Map<MethodSignature, List<GrMethod>> findMethodSignatures(GrMethod[] methods) {
|
||||
List<Pair<MethodSignature, GrMethod>> signatures = new ArrayList<Pair<MethodSignature, GrMethod>>();
|
||||
for (GrMethod method : methods) {
|
||||
List<MethodSignature> current = generateAllSignaturesForMethod(method, PsiSubstitutor.EMPTY);
|
||||
for (MethodSignature signature : current) {
|
||||
signatures.add(new Pair<MethodSignature, GrMethod>(signature, method));
|
||||
}
|
||||
}
|
||||
|
||||
THashMap<MethodSignature, List<GrMethod>> map = new THashMap<MethodSignature, List<GrMethod>>();
|
||||
for (Pair<MethodSignature, GrMethod> pair : signatures) {
|
||||
List<GrMethod> list = map.get(pair.first);
|
||||
if (list == null) {
|
||||
list = new ArrayList<GrMethod>();
|
||||
map.put(pair.first, list);
|
||||
}
|
||||
list.add(pair.second);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
private static MethodSignature generateSignature(String name,
|
||||
List<PsiType> paramTypes,
|
||||
PsiTypeParameter[] typeParameters,
|
||||
PsiSubstitutor substitutor) {
|
||||
return MethodSignatureUtil.createMethodSignature(name, paramTypes.toArray(new PsiType[paramTypes.size()]), typeParameters, substitutor);
|
||||
}
|
||||
}
|
||||
@@ -64,11 +64,11 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMe
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrClosureSignature;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.GrClosureSignatureUtil;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.GrClosureType;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GroovyScriptClass;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.JavaIdentifier;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.types.GrClosureSignatureUtil;
|
||||
import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil;
|
||||
import org.jetbrains.plugins.groovy.lang.resolve.processors.MethodResolverProcessor;
|
||||
|
||||
|
||||
@@ -238,4 +238,6 @@ public class GroovyHighlightingTest extends LightCodeInsightFixtureTestCase {
|
||||
public void testOverrideAnnotation() throws Exception {doTest();}
|
||||
|
||||
public void testClosureCallWithTupleTypeArgument() throws Exception {doTest();}
|
||||
|
||||
public void testMethodDuplicates() throws Exception {doTest();}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
def <error descr="foo(String, int) already defined">foo</error>(String s = "a", int i, double y = 4) {
|
||||
|
||||
}
|
||||
|
||||
def foo(int i, double y) {}
|
||||
|
||||
def <error descr="foo(String, int) already defined">foo</error>(String s, int i) {}
|
||||
|
||||
def foo(String s, double y){}
|
||||
Reference in New Issue
Block a user