diff --git a/ChangeLog.md b/ChangeLog.md index 69f2fcc1aa7..843237a0d53 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -482,6 +482,7 @@ These artifacts include extensions for the types available in the latter JDKs, s - [`KT-15640`](https://youtrack.jetbrains.com/issue/KT-15640) Extract Interface/Pull Up: Drop 'final' modifier when moving to an interface - [`KT-15639`](https://youtrack.jetbrains.com/issue/KT-15639) Extract Superclass/Interface/Pull Up: Add spaces between 'abstract' modifier and annotations - [`KT-15606`](https://youtrack.jetbrains.com/issue/KT-15606) Extract Interface/Pull Up: Warn about private members with usages in the original class +- [`KT-15635`](https://youtrack.jetbrains.com/issue/KT-15635) Extract Superclass/Interface: Fix bogus visibility warning inside a member when it's being moved as abstract #### Intention actions, inspections and quickfixes diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractClass/ExtractSuperRefactoring.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractClass/ExtractSuperRefactoring.kt index b454421e4a2..62bfbdbf8d3 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractClass/ExtractSuperRefactoring.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractClass/ExtractSuperRefactoring.kt @@ -145,7 +145,13 @@ class ExtractSuperRefactoring( else { KotlinMoveTargetForExistingElement(targetParent as KtElement) } - val conflictChecker = MoveConflictChecker(project, elementsToMove, moveTarget, originalClass) + val conflictChecker = MoveConflictChecker( + project, + elementsToMove, + moveTarget, + originalClass, + memberInfos.filter { it.isToAbstract }.mapNotNull { it.member } + ) project.runSynchronouslyWithProgress(RefactoringBundle.message("detecting.possible.conflicts"), true) { runReadAction { diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveDeclarations/moveConflictUtils.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveDeclarations/moveConflictUtils.kt index 69dfd937134..3f47cb1a0f9 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveDeclarations/moveConflictUtils.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/move/moveDeclarations/moveConflictUtils.kt @@ -51,7 +51,8 @@ class MoveConflictChecker( private val project: Project, private val elementsToMove: Collection, private val moveTarget: KotlinMoveTarget, - contextElement: KtElement + contextElement: KtElement, + private val doNotGoIn: Collection = emptyList() ) { private val resolutionFacade = contextElement.getResolutionFacade() @@ -148,7 +149,7 @@ class MoveConflictChecker( val sourceRoot = moveTarget.targetFile ?: return val targetModule = ModuleUtilCore.findModuleForFile(sourceRoot, project) ?: return val resolveScope = GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(targetModule) - for (declaration in elementsToMove) { + for (declaration in elementsToMove - doNotGoIn) { declaration.forEachDescendantOfType { refExpr -> val targetDescriptor = refExpr.analyze(BodyResolveMode.PARTIAL)[BindingContext.REFERENCE_TARGET, refExpr] ?: return@forEachDescendantOfType @@ -206,7 +207,7 @@ class MoveConflictChecker( fun checkVisibilityInDeclarations(conflicts: MultiMap) { val targetContainer = moveTarget.getContainerDescriptor() ?: return - for (declaration in elementsToMove) { + for (declaration in elementsToMove - doNotGoIn) { declaration.forEachDescendantOfType { refExpr -> refExpr.references .forEach { ref -> diff --git a/idea/testData/refactoring/extractInterface/noWarningOnVisibilityInsideAbstractedMember.kt b/idea/testData/refactoring/extractInterface/noWarningOnVisibilityInsideAbstractedMember.kt new file mode 100644 index 00000000000..52d0a57e278 --- /dev/null +++ b/idea/testData/refactoring/extractInterface/noWarningOnVisibilityInsideAbstractedMember.kt @@ -0,0 +1,12 @@ +// NAME: I +// SIBLING: +class BrokenRef { + private fun fun1() {} + fun fun2() {} + + // INFO: {checked: "true", toAbstract: "true"} + fun refer() { + fun1() + fun2() + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/extractInterface/noWarningOnVisibilityInsideAbstractedMember.kt.after b/idea/testData/refactoring/extractInterface/noWarningOnVisibilityInsideAbstractedMember.kt.after new file mode 100644 index 00000000000..03f12cd3f29 --- /dev/null +++ b/idea/testData/refactoring/extractInterface/noWarningOnVisibilityInsideAbstractedMember.kt.after @@ -0,0 +1,17 @@ +interface I { + // INFO: {checked: "true", toAbstract: "true"} + fun refer() +} + +// NAME: I +// SIBLING: +class BrokenRef : I { + private fun fun1() {} + fun fun2() {} + + // INFO: {checked: "true", toAbstract: "true"} + override fun refer() { + fun1() + fun2() + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/extractSuperclass/noWarningOnVisibilityInsideAbstractedMember.kt b/idea/testData/refactoring/extractSuperclass/noWarningOnVisibilityInsideAbstractedMember.kt new file mode 100644 index 00000000000..61eb80ada03 --- /dev/null +++ b/idea/testData/refactoring/extractSuperclass/noWarningOnVisibilityInsideAbstractedMember.kt @@ -0,0 +1,12 @@ +// NAME: A +// SIBLING: +class BrokenRef { + private fun fun1() {} + fun fun2() {} + + // INFO: {checked: "true", toAbstract: "true"} + fun refer() { + fun1() + fun2() + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/extractSuperclass/noWarningOnVisibilityInsideAbstractedMember.kt.after b/idea/testData/refactoring/extractSuperclass/noWarningOnVisibilityInsideAbstractedMember.kt.after new file mode 100644 index 00000000000..8d2ede37e88 --- /dev/null +++ b/idea/testData/refactoring/extractSuperclass/noWarningOnVisibilityInsideAbstractedMember.kt.after @@ -0,0 +1,17 @@ +abstract class A { + // INFO: {checked: "true", toAbstract: "true"} + abstract fun refer() +} + +// NAME: A +// SIBLING: +class BrokenRef : A() { + private fun fun1() {} + fun fun2() {} + + // INFO: {checked: "true", toAbstract: "true"} + override fun refer() { + fun1() + fun2() + } +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/refactoring/introduce/ExtractionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/refactoring/introduce/ExtractionTestGenerated.java index 802a0b32382..8e9af7a8f36 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/refactoring/introduce/ExtractionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/refactoring/introduce/ExtractionTestGenerated.java @@ -4295,6 +4295,12 @@ public class ExtractionTestGenerated extends AbstractExtractionTest { doExtractSuperclassTest(fileName); } + @TestMetadata("noWarningOnVisibilityInsideAbstractedMember.kt") + public void testNoWarningOnVisibilityInsideAbstractedMember() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/extractSuperclass/noWarningOnVisibilityInsideAbstractedMember.kt"); + doExtractSuperclassTest(fileName); + } + @TestMetadata("privateClass.kt") public void testPrivateClass() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/extractSuperclass/privateClass.kt"); @@ -4376,6 +4382,12 @@ public class ExtractionTestGenerated extends AbstractExtractionTest { doExtractInterfaceTest(fileName); } + @TestMetadata("noWarningOnVisibilityInsideAbstractedMember.kt") + public void testNoWarningOnVisibilityInsideAbstractedMember() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/extractInterface/noWarningOnVisibilityInsideAbstractedMember.kt"); + doExtractInterfaceTest(fileName); + } + @TestMetadata("privateMemberWithUsages.kt") public void testPrivateMemberWithUsages() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/extractInterface/privateMemberWithUsages.kt");