blob: 49a5c8a3978939982e70e22e5798d7f1bfdbd159 [file] [log] [blame]
/*
* 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.plugins.groovy.refactoring.changeSignature;
import com.intellij.psi.*;
import com.intellij.psi.util.MethodSignature;
import com.intellij.refactoring.util.RefactoringUIUtil;
import com.intellij.util.containers.MultiMap;
import org.jetbrains.plugins.groovy.lang.documentation.GroovyPresentationUtil;
import org.jetbrains.plugins.groovy.lang.psi.api.signatures.GrClosureSignature;
import org.jetbrains.plugins.groovy.lang.psi.api.signatures.GrRecursiveSignatureVisitor;
import org.jetbrains.plugins.groovy.lang.psi.api.signatures.GrSignature;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrAccessorMethod;
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.impl.GrClosureType;
import org.jetbrains.plugins.groovy.lang.psi.impl.signatures.GrClosureSignatureUtil;
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil;
import org.jetbrains.plugins.groovy.lang.psi.util.GroovyPropertyUtils;
import org.jetbrains.plugins.groovy.refactoring.GroovyRefactoringBundle;
import java.util.List;
/**
* @author Maxim.Medvedev
*/
public class GrMethodConflictUtil {
private GrMethodConflictUtil() {
}
public static void checkMethodConflicts(PsiClass clazz,
GrMethod prototype,
GrMethod refactoredMethod,
final MultiMap<PsiElement, String> conflicts, boolean excludeJavaConflicts) {
List<MethodSignature> prototypeSignatures = GrClosureSignatureUtil.generateAllSignaturesForMethod(prototype, PsiSubstitutor.EMPTY);
checkForClosurePropertySignatureOverload(clazz, prototype, refactoredMethod, conflicts, prototypeSignatures);
checkForMethodSignatureOverload(clazz, prototype, refactoredMethod, conflicts, excludeJavaConflicts, prototypeSignatures);
checkForAccessorOverloading(clazz, prototype, conflicts);
}
private static void checkForClosurePropertySignatureOverload(PsiClass clazz,
GrMethod prototype,
final GrMethod refactoredMethod,
final MultiMap<PsiElement, String> conflicts,
final List<MethodSignature> prototypeSignatures) {
final boolean isStatic = prototype.hasModifierProperty(PsiModifier.STATIC);
final String name = prototype.getName();
if (!GroovyPropertyUtils.isProperty(clazz, name, isStatic)) return;
final PsiMethod getter = GroovyPropertyUtils.findPropertyGetter(clazz, name, isStatic, true);
final PsiType returnType;
if (getter instanceof GrMethod) {
returnType = ((GrMethod)getter).getInferredReturnType();
}
else if (getter instanceof GrAccessorMethod) {
returnType = ((GrAccessorMethod)getter).getInferredReturnType();
}
else {
return;
}
if (!(returnType instanceof GrClosureType)) return;
final GrSignature signature = ((GrClosureType)returnType).getSignature();
signature.accept(new GrRecursiveSignatureVisitor() {
@Override
public void visitClosureSignature(GrClosureSignature signature) {
NextSignature:
for (MethodSignature prototypeSignature : prototypeSignatures) {
final GrClosureParameter[] params = signature.getParameters();
final PsiType[] types = prototypeSignature.getParameterTypes();
if (types.length != params.length) continue;
for (int i = 0; i < types.length; i++) {
if (!TypesUtil.isAssignableByMethodCallConversion(types[i], params[i].getType(), refactoredMethod.getParameterList())) {
continue NextSignature;
}
}
conflicts.putValue(getter, GroovyRefactoringBundle.message("refactored.method.will.cover.closure.property", name, RefactoringUIUtil.getDescription(getter.getContainingClass(), false)));
}
}
});
}
private static void checkForMethodSignatureOverload(PsiClass clazz,
GrMethod prototype,
GrMethod refactoredMethod,
MultiMap<PsiElement, String> conflicts,
boolean excludeJavaConflicts,
List<MethodSignature> prototypeSignatures) {
if (excludeJavaConflicts) {
prototypeSignatures.remove(prototype.getSignature(PsiSubstitutor.EMPTY));
}
String newName = prototype.getName();
PsiMethod[] methods = clazz.findMethodsByName(newName, false);
MultiMap<MethodSignature, PsiMethod> signatures = GrClosureSignatureUtil.findRawMethodSignatures(methods, clazz);
for (MethodSignature prototypeSignature : prototypeSignatures) {
for (PsiMethod method : signatures.get(prototypeSignature)) {
if (method != refactoredMethod) {
String signaturePresentation = GroovyPresentationUtil.getSignaturePresentation(prototypeSignature);
conflicts.putValue(method, GroovyRefactoringBundle.message("method.duplicate", signaturePresentation,
RefactoringUIUtil.getDescription(clazz, false)));
break;
}
}
}
}
private static void checkForAccessorOverloading(PsiClass clazz,
GrMethod prototype,
MultiMap<PsiElement, String> conflicts) {
if (GroovyPropertyUtils.isSimplePropertySetter(prototype)) {
String propertyName = GroovyPropertyUtils.getPropertyNameBySetter(prototype);
PsiMethod setter =
GroovyPropertyUtils.findPropertySetter(clazz, propertyName, prototype.hasModifierProperty(PsiModifier.STATIC), false);
if (setter instanceof GrAccessorMethod) {
conflicts.putValue(setter, GroovyRefactoringBundle.message("replace.setter.for.property", propertyName));
}
}
else if (GroovyPropertyUtils.isSimplePropertyGetter(prototype)) {
boolean isStatic = prototype.hasModifierProperty(PsiModifier.STATIC);
String propertyName = GroovyPropertyUtils.getPropertyNameByGetter(prototype);
PsiMethod getter = GroovyPropertyUtils.findPropertyGetter(clazz, propertyName, isStatic, false);
if (getter instanceof GrAccessorMethod) {
conflicts.putValue(getter, GroovyRefactoringBundle.message("replace.getter.for.property", propertyName));
}
}
}
}