mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
push down: warn if result in unrelated defaults/non-implemented method(IDEA-155595)
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
package com.intellij.refactoring.memberPushDown;
|
||||
|
||||
import com.intellij.codeInsight.AnnotationUtil;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.search.searches.ReferencesSearch;
|
||||
import com.intellij.psi.util.InheritanceUtil;
|
||||
@@ -29,6 +30,7 @@ import com.intellij.refactoring.util.classMembers.MemberInfo;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class PushDownConflicts {
|
||||
@@ -76,6 +78,26 @@ public class PushDownConflicts {
|
||||
if (annotation != null && myMovedMembers.contains(LambdaUtil.getFunctionalInterfaceMethod(myClass))) {
|
||||
myConflicts.putValue(annotation, RefactoringBundle.message("functional.interface.broken"));
|
||||
}
|
||||
boolean isAbstract = myClass.hasModifierProperty(PsiModifier.ABSTRACT);
|
||||
for (PsiMember member : myMovedMembers) {
|
||||
if (!member.hasModifierProperty(PsiModifier.STATIC) && member instanceof PsiMethod && !myAbstractMembers.contains(member)) {
|
||||
Set<PsiClass> unrelatedDefaults = new LinkedHashSet<>();
|
||||
for (PsiMethod superMethod : ((PsiMethod)member).findSuperMethods()) {
|
||||
if (!isAbstract && superMethod.hasModifierProperty(PsiModifier.ABSTRACT)) {
|
||||
myConflicts.putValue(member, "Non abstract " + RefactoringUIUtil.getDescription(myClass, false) + " will miss implementation of " + RefactoringUIUtil.getDescription(superMethod, false));
|
||||
break;
|
||||
}
|
||||
if (superMethod.hasModifierProperty(PsiModifier.DEFAULT)) {
|
||||
unrelatedDefaults.add(superMethod.getContainingClass());
|
||||
if (unrelatedDefaults.size() > 1) {
|
||||
myConflicts.putValue(member, CommonRefactoringUtil.capitalize(RefactoringUIUtil.getDescription(myClass, false) + " will inherit unrelated defaults from " +
|
||||
StringUtil.join(unrelatedDefaults, aClass -> RefactoringUIUtil.getDescription(aClass, false)," and ")));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void checkTargetClassConflicts(final PsiElement targetElement, final PsiElement context) {
|
||||
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
|
||||
interface A {
|
||||
default void foo() {}
|
||||
}
|
||||
|
||||
interface I {
|
||||
default void foo() { }
|
||||
}
|
||||
|
||||
class B implements I, A {
|
||||
@Override
|
||||
public void fo<caret>o() { }
|
||||
}
|
||||
|
||||
class C extends B {
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
|
||||
interface A {
|
||||
default void foo() {}
|
||||
}
|
||||
|
||||
interface I {
|
||||
default void foo() { }
|
||||
}
|
||||
|
||||
class B implements I, A {
|
||||
}
|
||||
|
||||
class C extends B {
|
||||
@Override
|
||||
public void foo() { }
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
abstract class A {
|
||||
abstract void foo();
|
||||
}
|
||||
|
||||
class B extends A {
|
||||
@Override
|
||||
public void fo<caret>o() { }
|
||||
}
|
||||
|
||||
class C extends B {
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
abstract class A {
|
||||
abstract void foo();
|
||||
}
|
||||
|
||||
class B extends A {
|
||||
}
|
||||
|
||||
class C extends B {
|
||||
@Override
|
||||
public void foo() { }
|
||||
}
|
||||
@@ -27,7 +27,9 @@ import com.intellij.util.containers.MultiMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* @author anna
|
||||
@@ -107,11 +109,31 @@ public class PushDownTest extends LightRefactoringTestCase {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testClassShouldBeAbstractConflict() {
|
||||
doTest(conflicts -> {
|
||||
assertSameElements(conflicts.values(), Collections.singletonList("Non abstract class <b><code>B</code></b> will miss implementation of method <b><code>foo()</code></b>"));
|
||||
});
|
||||
}
|
||||
|
||||
public void testClassInheritsUnrelatedDefaultsConflict() {
|
||||
doTest(conflicts -> {
|
||||
assertSameElements(conflicts.values(), Collections.singletonList("Class <b><code>B</code></b> will inherit unrelated defaults from interface <b><code>I</code></b> and interface <b><code>A</code></b>"));
|
||||
});
|
||||
}
|
||||
|
||||
private void doTest() {
|
||||
doTest(false);
|
||||
}
|
||||
|
||||
private void doTest(final boolean failure) {
|
||||
doTest(conflicts -> {
|
||||
if (failure == conflicts.isEmpty()) {
|
||||
fail(failure ? "Conflict was not detected" : "False conflict was detected");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void doTest(final Consumer<MultiMap<PsiElement, String>> checkConflicts) {
|
||||
configureByFile(BASE_PATH + getTestName(false) + ".java");
|
||||
|
||||
final PsiElement targetElement = TargetElementUtil.findTargetElement(getEditor(), TargetElementUtil.ELEMENT_NAME_ACCEPTED);
|
||||
@@ -147,9 +169,7 @@ public class PushDownTest extends LightRefactoringTestCase {
|
||||
new DocCommentPolicy(DocCommentPolicy.ASIS)) {
|
||||
@Override
|
||||
protected boolean showConflicts(@NotNull MultiMap<PsiElement, String> conflicts, UsageInfo[] usages) {
|
||||
if (failure == conflicts.isEmpty()) {
|
||||
fail(failure ? "Conflict was not detected" : "False conflict was detected");
|
||||
}
|
||||
checkConflicts.accept(conflicts);
|
||||
return true;
|
||||
}
|
||||
}.run();
|
||||
|
||||
Reference in New Issue
Block a user