fix for changing parameter types for method which used to extend the generic-parameter-method which was refactored to bounded wildcards and "both method signatures have same erasure" error appeared as a result

This commit is contained in:
Alexey Kudravtsev
2018-09-14 16:01:02 +03:00
parent abb176a63a
commit 544c3b670f
7 changed files with 172 additions and 1 deletions
@@ -455,4 +455,9 @@ public abstract class QuickFixFactory {
@NotNull
public abstract IntentionAction createPushDownMethodFix();
@NotNull
public IntentionAction createSameErasureButDifferentMethodsFix(@NotNull PsiMethod method, @NotNull PsiMethod superMethod) {
throw new AbstractMethodError();
}
}
@@ -689,7 +689,11 @@ public class GenericsHighlightUtil {
"generics.methods.have.same.erasure.hide" :
"generics.methods.have.same.erasure.override";
String description = JavaErrorMessages.message(key, HighlightMethodUtil.createClashMethodMessage(method, superMethod, !sameClass));
return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(textRange).descriptionAndTooltip(description).create();
HighlightInfo info =
HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(textRange).descriptionAndTooltip(description).create();
QuickFixAction.registerQuickFixAction(info, QUICK_FIX_FACTORY.createSameErasureButDifferentMethodsFix(method, superMethod));
return info;
}
static HighlightInfo checkTypeParameterInstantiation(@NotNull PsiNewExpression expression) {
@@ -0,0 +1,104 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.codeInsight.intention.impl;
import com.intellij.codeInspection.LocalQuickFixAndIntentionActionOnPsiElement;
import com.intellij.openapi.application.TransactionGuard;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.util.JavaClassSupers;
import com.intellij.psi.util.MethodSignature;
import com.intellij.psi.util.MethodSignatureUtil;
import com.intellij.refactoring.changeSignature.ChangeSignatureProcessor;
import com.intellij.refactoring.changeSignature.ParameterInfoImpl;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
// @Override void f(List<String> p); -> @Override void f(List<? super String> p);
public class SameErasureButDifferentMethodsFix extends LocalQuickFixAndIntentionActionOnPsiElement {
private final SmartPsiElementPointer<PsiMethod> methodPtr;
public SameErasureButDifferentMethodsFix(@NotNull PsiMethod method, @NotNull PsiMethod superMethod) {
super(superMethod);
methodPtr = SmartPointerManager.getInstance(method.getProject()).createSmartPsiElementPointer(method);
}
@Override
public void invoke(@NotNull Project project,
@NotNull PsiFile file,
@Nullable Editor editor,
@NotNull PsiElement startElement,
@NotNull PsiElement endElement) {
if (!isAvailable(project, file, startElement, endElement)) return;
PsiMethod superMethod = (PsiMethod)startElement;
PsiMethod method = methodPtr.getElement();
if (method == null || !method.isValid()) return;
PsiClass containingClass = method.getContainingClass();
PsiClass superContainingClass = superMethod.getContainingClass();
if (containingClass == null || superContainingClass == null) return;
PsiSubstitutor superSubstitutor = JavaClassSupers.getInstance()
.getSuperClassSubstitutor(superContainingClass, containingClass, containingClass.getResolveScope(), PsiSubstitutor.EMPTY);
if (superSubstitutor == null) return;
PsiParameter[] parameters = method.getParameterList().getParameters();
PsiParameter[] superParameters = superMethod.getParameterList().getParameters();
if (parameters.length != superParameters.length) return;
ParameterInfoImpl[] infos = new ParameterInfoImpl[parameters.length];
for (int i = 0; i < parameters.length; i++) {
PsiParameter parameter = parameters[i];
PsiParameter superParameter = superParameters[i];
PsiType parameterType = parameter.getType();
PsiType superParameterType = superSubstitutor.substitute(superParameter.getType());
infos[i] = new ParameterInfoImpl(i, parameter.getName(), superParameterType);
}
ChangeSignatureProcessor processor =
new ChangeSignatureProcessor(project, method, false, null, method.getName(), method.getReturnType(), infos);
TransactionGuard.submitTransaction(project, processor);
}
@Override
public boolean isAvailable(@NotNull Project project,
@NotNull PsiFile file,
@NotNull PsiElement startElement,
@NotNull PsiElement endElement) {
PsiMethod superMethod = (PsiMethod)startElement;
PsiMethod method = methodPtr.getElement();
if (method == null || !method.isValid()) return false;
JavaPsiFacade facade = JavaPsiFacade.getInstance(project);
PsiClass containingClass = method.getContainingClass();
PsiClass superContainingClass = superMethod.getContainingClass();
if (containingClass == null || superContainingClass == null) return false;
if (!facade.getResolveHelper().isAccessible(superMethod, containingClass, null)) return false;
MethodSignature signature = method.getSignature(PsiSubstitutor.EMPTY);
PsiSubstitutor superSubstitutor = JavaClassSupers.getInstance()
.getSuperClassSubstitutor(superContainingClass, containingClass, containingClass.getResolveScope(), PsiSubstitutor.EMPTY);
if (superSubstitutor == null) return false;
MethodSignature superSignature = superMethod.getSignature(superSubstitutor);
if (method.getParameterList().getParametersCount() != superMethod.getParameterList().getParametersCount()) return false;
return !signature.equals(superSignature) && MethodSignatureUtil.areSignaturesErasureEqual(signature, superSignature);
}
@NotNull
@Override
public String getText() {
PsiMethod method = methodPtr.getElement();
if (method == null || !method.isValid()) return getFamilyName();
return "Fix method '"+method.getName()+"' parameters with bounded wildcards";
}
@Nls
@NotNull
@Override
public String getFamilyName() {
return "Fix bounded wildcards";
}
@Override
public boolean startInWriteAction() {
return false;
}
}
@@ -16,6 +16,7 @@ import com.intellij.codeInsight.intention.QuickFixFactory;
import com.intellij.codeInsight.intention.impl.CreateClassInPackageInModuleFix;
import com.intellij.codeInsight.intention.impl.ReplaceAssignmentWithComparisonFix;
import com.intellij.codeInsight.intention.impl.RunRefactoringAction;
import com.intellij.codeInsight.intention.impl.SameErasureButDifferentMethodsFix;
import com.intellij.codeInspection.*;
import com.intellij.codeInspection.deadCode.UnusedDeclarationInspectionBase;
import com.intellij.codeInspection.ex.EntryPointsManagerBase;
@@ -926,4 +927,10 @@ public class QuickFixFactoryImpl extends QuickFixFactory {
}
};
}
@NotNull
@Override
public IntentionAction createSameErasureButDifferentMethodsFix(@NotNull PsiMethod method, @NotNull PsiMethod superMethod) {
return new SameErasureButDifferentMethodsFix(method, superMethod);
}
}
@@ -0,0 +1,17 @@
// "Fix method 'foo' parameters with bounded wildcards" "true"
import java.util.List;
interface Xo {
void foo(List<? super String> s);
}
public class ErrWarn implements Xo {
public void <caret>foo(List<? super String> s) {
}
}
class D extends ErrWarn {
@Override
public void foo(List<? super String> s) {
super.foo(s);
}
}
@@ -0,0 +1,17 @@
// "Fix method 'foo' parameters with bounded wildcards" "true"
import java.util.List;
interface Xo {
void foo(List<? super String> s);
}
public class ErrWarn implements Xo {
public void <caret>foo(List<String> s) {
}
}
class D extends ErrWarn {
@Override
public void foo(List<String> s) {
super.foo(s);
}
}
@@ -0,0 +1,17 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.java.codeInsight.intention;
import com.intellij.codeInsight.daemon.LightIntentionActionTestCase;
import com.intellij.refactoring.BaseRefactoringProcessor;
public class BoundedWildcardFixTest extends LightIntentionActionTestCase {
@Override
protected String getBasePath() {
return "/codeInsight/daemonCodeAnalyzer/quickFix/boundedWildcard";
}
@Override
protected void doSingleTest(String fileSuffix, String testDataPath) {
BaseRefactoringProcessor.ConflictsInTestsException.withIgnoredConflicts(()-> super.doSingleTest(fileSuffix, testDataPath));
}
}