From 9c61f421214346f6da9b02dcf4a69886dd5d1630 Mon Sep 17 00:00:00 2001 From: Dmitry Gridin Date: Tue, 22 Oct 2019 21:01:59 +0700 Subject: [PATCH] ChangeVisibilityModifierIntention: should affect all actual/expect declarations #KT-29737 Fixed --- .../kotlin/idea/util/expectActualUtil.kt | 6 ++++ .../ChangeVisibilityModifierIntention.kt | 30 ++++++++++++++----- .../changeModifier/internal/common/Sample.kt | 3 ++ .../internal/common/Sample.kt.after | 3 ++ .../changeModifier/internal/js/SampleJvm.kt | 1 + .../internal/js/SampleJvm.kt.after | 1 + .../changeModifier/internal/jvm/SampleJs.kt | 1 + .../internal/jvm/SampleJs.kt.after | 1 + .../changeModifier/public/common/Sample.kt | 1 + .../public/common/Sample.kt.after | 1 + .../changeModifier/public/js/SampleJvm.kt | 3 ++ .../public/js/SampleJvm.kt.after | 3 ++ .../changeModifier/public/jvm/SampleJs.kt | 1 + .../public/jvm/SampleJs.kt.after | 1 + .../QuickFixMultiModuleTestGenerated.java | 23 ++++++++++++++ 15 files changed, 71 insertions(+), 8 deletions(-) create mode 100644 idea/testData/multiModuleQuickFix/changeModifier/internal/common/Sample.kt create mode 100644 idea/testData/multiModuleQuickFix/changeModifier/internal/common/Sample.kt.after create mode 100644 idea/testData/multiModuleQuickFix/changeModifier/internal/js/SampleJvm.kt create mode 100644 idea/testData/multiModuleQuickFix/changeModifier/internal/js/SampleJvm.kt.after create mode 100644 idea/testData/multiModuleQuickFix/changeModifier/internal/jvm/SampleJs.kt create mode 100644 idea/testData/multiModuleQuickFix/changeModifier/internal/jvm/SampleJs.kt.after create mode 100644 idea/testData/multiModuleQuickFix/changeModifier/public/common/Sample.kt create mode 100644 idea/testData/multiModuleQuickFix/changeModifier/public/common/Sample.kt.after create mode 100644 idea/testData/multiModuleQuickFix/changeModifier/public/js/SampleJvm.kt create mode 100644 idea/testData/multiModuleQuickFix/changeModifier/public/js/SampleJvm.kt.after create mode 100644 idea/testData/multiModuleQuickFix/changeModifier/public/jvm/SampleJs.kt create mode 100644 idea/testData/multiModuleQuickFix/changeModifier/public/jvm/SampleJs.kt.after diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/util/expectActualUtil.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/util/expectActualUtil.kt index 19f6e9f71f7..7c6b0a69400 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/util/expectActualUtil.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/util/expectActualUtil.kt @@ -145,4 +145,10 @@ fun KtDeclaration.runOnExpectAndAllActuals(checkExpect: Boolean = true, f: (KtDe } else if (!checkExpect || isExpectDeclaration()) { actualsForExpected().forEach { f(it) } } +} + +fun KtDeclaration.collectAllExpectAndActualDeclaration(): Set = when { + isExpectDeclaration() -> actualsForExpected() + this + hasActualModifier() -> liftToExpected()?.let { it.actualsForExpected() + it }.orEmpty() + else -> emptySet() } \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/ChangeVisibilityModifierIntention.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/ChangeVisibilityModifierIntention.kt index 78cb8849bb1..9488d8e68e4 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/ChangeVisibilityModifierIntention.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/ChangeVisibilityModifierIntention.kt @@ -23,17 +23,17 @@ import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithVisibility import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.idea.core.* +import org.jetbrains.kotlin.idea.util.application.executeWriteCommand +import org.jetbrains.kotlin.idea.util.collectAllExpectAndActualDeclaration import org.jetbrains.kotlin.lexer.KtModifierKeywordToken import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.psi.* -import org.jetbrains.kotlin.psi.psiUtil.startOffset -import org.jetbrains.kotlin.psi.psiUtil.toVisibility -import org.jetbrains.kotlin.psi.psiUtil.visibilityModifier -import org.jetbrains.kotlin.psi.psiUtil.visibilityModifierType +import org.jetbrains.kotlin.psi.psiUtil.* open class ChangeVisibilityModifierIntention protected constructor( val modifier: KtModifierKeywordToken ) : SelfTargetingRangeIntention(KtDeclaration::class.java, "Make ${modifier.value}") { + override fun startInWriteAction(): Boolean = false override fun applicabilityRange(element: KtDeclaration): TextRange? { val modifierList = element.modifierList @@ -46,11 +46,12 @@ open class ChangeVisibilityModifierIntention protected constructor( if (descriptor.visibility == targetVisibility) return null if (modifierList?.hasModifier(KtTokens.OVERRIDE_KEYWORD) == true) { - val callableDescriptor = descriptor as? CallableDescriptor ?: return null + val callableDescriptor = descriptor as? CallableDescriptor ?: return null // cannot make visibility less than (or non-comparable with) any of the supers if (callableDescriptor.overriddenDescriptors .map { Visibilities.compare(it.visibility, targetVisibility) } - .any { it == null || it > 0 }) return null + .any { it == null || it > 0 } + ) return null } text = defaultText @@ -80,8 +81,21 @@ open class ChangeVisibilityModifierIntention protected constructor( } override fun applyTo(element: KtDeclaration, editor: Editor?) { - element.setVisibility(modifier) - if (element is KtPropertyAccessor) element.modifierList?.nextSibling?.replace(KtPsiFactory(element).createWhiteSpace()) + val pointers = element.collectAllExpectAndActualDeclaration().map { it.createSmartPointer() } + + val project = element.project + val factory = KtPsiFactory(project) + project.executeWriteCommand("Change visibility modifier") { + for (pointer in pointers) { + val declaration = pointer.element ?: continue + + declaration.setVisibility(modifier) + if (declaration is KtPropertyAccessor) { + declaration.modifierList?.nextSibling?.replace(factory.createWhiteSpace()) + } + } + } + } private fun noModifierYetApplicabilityRange(declaration: KtDeclaration): TextRange? { diff --git a/idea/testData/multiModuleQuickFix/changeModifier/internal/common/Sample.kt b/idea/testData/multiModuleQuickFix/changeModifier/internal/common/Sample.kt new file mode 100644 index 00000000000..f80733a671e --- /dev/null +++ b/idea/testData/multiModuleQuickFix/changeModifier/internal/common/Sample.kt @@ -0,0 +1,3 @@ +// "Make internal" "true" + +expect class Sample \ No newline at end of file diff --git a/idea/testData/multiModuleQuickFix/changeModifier/internal/common/Sample.kt.after b/idea/testData/multiModuleQuickFix/changeModifier/internal/common/Sample.kt.after new file mode 100644 index 00000000000..586e5e7e272 --- /dev/null +++ b/idea/testData/multiModuleQuickFix/changeModifier/internal/common/Sample.kt.after @@ -0,0 +1,3 @@ +// "Make internal" "true" + +internal expect class Sample \ No newline at end of file diff --git a/idea/testData/multiModuleQuickFix/changeModifier/internal/js/SampleJvm.kt b/idea/testData/multiModuleQuickFix/changeModifier/internal/js/SampleJvm.kt new file mode 100644 index 00000000000..cd96280e319 --- /dev/null +++ b/idea/testData/multiModuleQuickFix/changeModifier/internal/js/SampleJvm.kt @@ -0,0 +1 @@ +actual class Sample \ No newline at end of file diff --git a/idea/testData/multiModuleQuickFix/changeModifier/internal/js/SampleJvm.kt.after b/idea/testData/multiModuleQuickFix/changeModifier/internal/js/SampleJvm.kt.after new file mode 100644 index 00000000000..7c62d4fb451 --- /dev/null +++ b/idea/testData/multiModuleQuickFix/changeModifier/internal/js/SampleJvm.kt.after @@ -0,0 +1 @@ +internal actual class Sample \ No newline at end of file diff --git a/idea/testData/multiModuleQuickFix/changeModifier/internal/jvm/SampleJs.kt b/idea/testData/multiModuleQuickFix/changeModifier/internal/jvm/SampleJs.kt new file mode 100644 index 00000000000..cd96280e319 --- /dev/null +++ b/idea/testData/multiModuleQuickFix/changeModifier/internal/jvm/SampleJs.kt @@ -0,0 +1 @@ +actual class Sample \ No newline at end of file diff --git a/idea/testData/multiModuleQuickFix/changeModifier/internal/jvm/SampleJs.kt.after b/idea/testData/multiModuleQuickFix/changeModifier/internal/jvm/SampleJs.kt.after new file mode 100644 index 00000000000..7c62d4fb451 --- /dev/null +++ b/idea/testData/multiModuleQuickFix/changeModifier/internal/jvm/SampleJs.kt.after @@ -0,0 +1 @@ +internal actual class Sample \ No newline at end of file diff --git a/idea/testData/multiModuleQuickFix/changeModifier/public/common/Sample.kt b/idea/testData/multiModuleQuickFix/changeModifier/public/common/Sample.kt new file mode 100644 index 00000000000..72b5cba1b1b --- /dev/null +++ b/idea/testData/multiModuleQuickFix/changeModifier/public/common/Sample.kt @@ -0,0 +1 @@ +internal expect class Sample \ No newline at end of file diff --git a/idea/testData/multiModuleQuickFix/changeModifier/public/common/Sample.kt.after b/idea/testData/multiModuleQuickFix/changeModifier/public/common/Sample.kt.after new file mode 100644 index 00000000000..8a98985c8b6 --- /dev/null +++ b/idea/testData/multiModuleQuickFix/changeModifier/public/common/Sample.kt.after @@ -0,0 +1 @@ +expect class Sample \ No newline at end of file diff --git a/idea/testData/multiModuleQuickFix/changeModifier/public/js/SampleJvm.kt b/idea/testData/multiModuleQuickFix/changeModifier/public/js/SampleJvm.kt new file mode 100644 index 00000000000..8138a011727 --- /dev/null +++ b/idea/testData/multiModuleQuickFix/changeModifier/public/js/SampleJvm.kt @@ -0,0 +1,3 @@ +// "Make public" "true" + +internal actual class Sample \ No newline at end of file diff --git a/idea/testData/multiModuleQuickFix/changeModifier/public/js/SampleJvm.kt.after b/idea/testData/multiModuleQuickFix/changeModifier/public/js/SampleJvm.kt.after new file mode 100644 index 00000000000..a4772329961 --- /dev/null +++ b/idea/testData/multiModuleQuickFix/changeModifier/public/js/SampleJvm.kt.after @@ -0,0 +1,3 @@ +// "Make public" "true" + +actual class Sample \ No newline at end of file diff --git a/idea/testData/multiModuleQuickFix/changeModifier/public/jvm/SampleJs.kt b/idea/testData/multiModuleQuickFix/changeModifier/public/jvm/SampleJs.kt new file mode 100644 index 00000000000..7c62d4fb451 --- /dev/null +++ b/idea/testData/multiModuleQuickFix/changeModifier/public/jvm/SampleJs.kt @@ -0,0 +1 @@ +internal actual class Sample \ No newline at end of file diff --git a/idea/testData/multiModuleQuickFix/changeModifier/public/jvm/SampleJs.kt.after b/idea/testData/multiModuleQuickFix/changeModifier/public/jvm/SampleJs.kt.after new file mode 100644 index 00000000000..cd96280e319 --- /dev/null +++ b/idea/testData/multiModuleQuickFix/changeModifier/public/jvm/SampleJs.kt.after @@ -0,0 +1 @@ +actual class Sample \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiModuleTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiModuleTestGenerated.java index 3973bc556d9..74a2e119505 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiModuleTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiModuleTestGenerated.java @@ -209,6 +209,29 @@ public class QuickFixMultiModuleTestGenerated extends AbstractQuickFixMultiModul } } + @TestMetadata("idea/testData/multiModuleQuickFix/changeModifier") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class ChangeModifier extends AbstractQuickFixMultiModuleTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath); + } + + public void testAllFilesPresentInChangeModifier() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/multiModuleQuickFix/changeModifier"), Pattern.compile("^([^\\.]+)$"), TargetBackend.ANY, true); + } + + @TestMetadata("internal") + public void testInternal() throws Exception { + runTest("idea/testData/multiModuleQuickFix/changeModifier/internal/"); + } + + @TestMetadata("public") + public void testPublic() throws Exception { + runTest("idea/testData/multiModuleQuickFix/changeModifier/public/"); + } + } + @TestMetadata("idea/testData/multiModuleQuickFix/changeSignature") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)