From f0f6a252a52441f347ae06a85084f4cee2c22d67 Mon Sep 17 00:00:00 2001 From: Toshiaki Kameyama Date: Thu, 17 Aug 2017 13:06:13 +0300 Subject: [PATCH] Offer to make INVISIBLE_MEMBER protected if referenced from subclass So #KT-19614 Fixed --- .../idea/quickfix/MakeVisibleFactory.kt | 12 +++++-- .../invisibleFake/methodToNotProtected.kt | 15 ++++++++ .../invisibleFake/methodToProtected.kt | 12 +++++++ .../invisibleFake/methodToProtected.kt.after | 12 +++++++ .../invisibleFake/methodToProtected2.kt | 14 ++++++++ .../invisibleFake/methodToProtected2.kt.after | 14 ++++++++ .../invisibleFake/propertyToNotProtected.kt | 15 ++++++++ .../invisibleFake/propertyToProtected.kt | 11 ++++++ .../propertyToProtected.kt.after | 11 ++++++ .../invisibleFake/propertyToProtected2.kt | 13 +++++++ .../propertyToProtected2.kt.after | 13 +++++++ .../idea/quickfix/QuickFixTestGenerated.java | 36 +++++++++++++++++++ 12 files changed, 176 insertions(+), 2 deletions(-) create mode 100644 idea/testData/quickfix/increaseVisibility/invisibleFake/methodToNotProtected.kt create mode 100644 idea/testData/quickfix/increaseVisibility/invisibleFake/methodToProtected.kt create mode 100644 idea/testData/quickfix/increaseVisibility/invisibleFake/methodToProtected.kt.after create mode 100644 idea/testData/quickfix/increaseVisibility/invisibleFake/methodToProtected2.kt create mode 100644 idea/testData/quickfix/increaseVisibility/invisibleFake/methodToProtected2.kt.after create mode 100644 idea/testData/quickfix/increaseVisibility/invisibleFake/propertyToNotProtected.kt create mode 100644 idea/testData/quickfix/increaseVisibility/invisibleFake/propertyToProtected.kt create mode 100644 idea/testData/quickfix/increaseVisibility/invisibleFake/propertyToProtected.kt.after create mode 100644 idea/testData/quickfix/increaseVisibility/invisibleFake/propertyToProtected2.kt create mode 100644 idea/testData/quickfix/increaseVisibility/invisibleFake/propertyToProtected2.kt.after diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/MakeVisibleFactory.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/MakeVisibleFactory.kt index 48d2fbfaa7a..bdda0f3c2e1 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/MakeVisibleFactory.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/MakeVisibleFactory.kt @@ -17,21 +17,25 @@ package org.jetbrains.kotlin.idea.quickfix import com.intellij.codeInsight.intention.IntentionAction +import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithVisibility import org.jetbrains.kotlin.descriptors.Visibilities.* import org.jetbrains.kotlin.diagnostics.Diagnostic import org.jetbrains.kotlin.diagnostics.DiagnosticFactory3 import org.jetbrains.kotlin.idea.caches.resolve.analyze +import org.jetbrains.kotlin.idea.search.usagesSearch.descriptor import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.KtModifierListOwner +import org.jetbrains.kotlin.psi.psiUtil.containingClass import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils import org.jetbrains.kotlin.resolve.DescriptorUtils +import org.jetbrains.kotlin.resolve.descriptorUtil.getAllSuperclassesWithoutAny import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode -object MakeVisibleFactory : KotlinIntentionActionsFactory() { +object MakeVisibleFactory : KotlinIntentionActionsFactory() { override fun doCreateActions(diagnostic: Diagnostic): List { val element = diagnostic.psiElement as? KtElement ?: return emptyList() val context = element.analyze(BodyResolveMode.PARTIAL) @@ -44,7 +48,11 @@ object MakeVisibleFactory : KotlinIntentionActionsFactory() { val module = DescriptorUtils.getContainingModule(descriptor) val targetVisibilities = when (descriptor.visibility) { - PRIVATE, INVISIBLE_FAKE -> if (module != usageModule) listOf(PUBLIC) else listOf(PUBLIC, INTERNAL) + PRIVATE, INVISIBLE_FAKE -> mutableListOf(PUBLIC).apply { + if (module == usageModule) add(INTERNAL) + val superClasses = (element.containingClass()?.descriptor as? ClassDescriptor)?.getAllSuperclassesWithoutAny() + if (superClasses?.contains(declaration.containingClass()?.descriptor) == true) add(PROTECTED) + } else -> listOf(PUBLIC) } diff --git a/idea/testData/quickfix/increaseVisibility/invisibleFake/methodToNotProtected.kt b/idea/testData/quickfix/increaseVisibility/invisibleFake/methodToNotProtected.kt new file mode 100644 index 00000000000..5eecc54a17b --- /dev/null +++ b/idea/testData/quickfix/increaseVisibility/invisibleFake/methodToNotProtected.kt @@ -0,0 +1,15 @@ +// "Make 'doSth' protected" "false" +// ACTION: Make 'doSth' public +// ACTION: Make 'doSth' internal +// ERROR: Cannot access 'doSth': it is private in 'A' + +class A { + private fun doSth() { + } +} + +class B { + fun bar() { + A().doSth() + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/increaseVisibility/invisibleFake/methodToProtected.kt b/idea/testData/quickfix/increaseVisibility/invisibleFake/methodToProtected.kt new file mode 100644 index 00000000000..de8d09ad5c3 --- /dev/null +++ b/idea/testData/quickfix/increaseVisibility/invisibleFake/methodToProtected.kt @@ -0,0 +1,12 @@ +// "Make 'doSth' protected" "true" + +open class A { + private fun doSth() { + } +} + +class B : A() { + fun bar() { + doSth() + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/increaseVisibility/invisibleFake/methodToProtected.kt.after b/idea/testData/quickfix/increaseVisibility/invisibleFake/methodToProtected.kt.after new file mode 100644 index 00000000000..272eb77d741 --- /dev/null +++ b/idea/testData/quickfix/increaseVisibility/invisibleFake/methodToProtected.kt.after @@ -0,0 +1,12 @@ +// "Make 'doSth' protected" "true" + +open class A { + protected fun doSth() { + } +} + +class B : A() { + fun bar() { + doSth() + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/increaseVisibility/invisibleFake/methodToProtected2.kt b/idea/testData/quickfix/increaseVisibility/invisibleFake/methodToProtected2.kt new file mode 100644 index 00000000000..c17df4995a3 --- /dev/null +++ b/idea/testData/quickfix/increaseVisibility/invisibleFake/methodToProtected2.kt @@ -0,0 +1,14 @@ +// "Make 'doSth' protected" "true" + +open class A { + private fun doSth() { + } +} + +open class B : A() + +class C : B() { + fun bar() { + doSth() + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/increaseVisibility/invisibleFake/methodToProtected2.kt.after b/idea/testData/quickfix/increaseVisibility/invisibleFake/methodToProtected2.kt.after new file mode 100644 index 00000000000..6b352f4847f --- /dev/null +++ b/idea/testData/quickfix/increaseVisibility/invisibleFake/methodToProtected2.kt.after @@ -0,0 +1,14 @@ +// "Make 'doSth' protected" "true" + +open class A { + protected fun doSth() { + } +} + +open class B : A() + +class C : B() { + fun bar() { + doSth() + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/increaseVisibility/invisibleFake/propertyToNotProtected.kt b/idea/testData/quickfix/increaseVisibility/invisibleFake/propertyToNotProtected.kt new file mode 100644 index 00000000000..9b0d3b743e7 --- /dev/null +++ b/idea/testData/quickfix/increaseVisibility/invisibleFake/propertyToNotProtected.kt @@ -0,0 +1,15 @@ +// "Make 'foo' protected" "false" +// ACTION: Make 'foo' public +// ACTION: Make 'foo' internal +// ACTION: Introduce local variable +// ERROR: Cannot access 'foo': it is private in 'A' + +class A { + private val foo = 1 +} + +class B { + fun bar() { + A().foo + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/increaseVisibility/invisibleFake/propertyToProtected.kt b/idea/testData/quickfix/increaseVisibility/invisibleFake/propertyToProtected.kt new file mode 100644 index 00000000000..5af6b225961 --- /dev/null +++ b/idea/testData/quickfix/increaseVisibility/invisibleFake/propertyToProtected.kt @@ -0,0 +1,11 @@ +// "Make 'foo' protected" "true" + +open class A { + private val foo = 1 +} + +class B : A() { + fun bar() { + foo + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/increaseVisibility/invisibleFake/propertyToProtected.kt.after b/idea/testData/quickfix/increaseVisibility/invisibleFake/propertyToProtected.kt.after new file mode 100644 index 00000000000..60812698aba --- /dev/null +++ b/idea/testData/quickfix/increaseVisibility/invisibleFake/propertyToProtected.kt.after @@ -0,0 +1,11 @@ +// "Make 'foo' protected" "true" + +open class A { + protected val foo = 1 +} + +class B : A() { + fun bar() { + foo + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/increaseVisibility/invisibleFake/propertyToProtected2.kt b/idea/testData/quickfix/increaseVisibility/invisibleFake/propertyToProtected2.kt new file mode 100644 index 00000000000..1e1248448dd --- /dev/null +++ b/idea/testData/quickfix/increaseVisibility/invisibleFake/propertyToProtected2.kt @@ -0,0 +1,13 @@ +// "Make 'foo' protected" "true" + +open class A { + private val foo = 1 +} + +open class B : A() + +class C : B() { + fun bar() { + foo + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/increaseVisibility/invisibleFake/propertyToProtected2.kt.after b/idea/testData/quickfix/increaseVisibility/invisibleFake/propertyToProtected2.kt.after new file mode 100644 index 00000000000..635fe75f9f6 --- /dev/null +++ b/idea/testData/quickfix/increaseVisibility/invisibleFake/propertyToProtected2.kt.after @@ -0,0 +1,13 @@ +// "Make 'foo' protected" "true" + +open class A { + protected val foo = 1 +} + +open class B : A() + +class C : B() { + fun bar() { + foo + } +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java index bfbb6670bf7..9d1b2967ee4 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java @@ -6301,6 +6301,24 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { doTest(fileName); } + @TestMetadata("methodToNotProtected.kt") + public void testMethodToNotProtected() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/increaseVisibility/invisibleFake/methodToNotProtected.kt"); + doTest(fileName); + } + + @TestMetadata("methodToProtected.kt") + public void testMethodToProtected() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/increaseVisibility/invisibleFake/methodToProtected.kt"); + doTest(fileName); + } + + @TestMetadata("methodToProtected2.kt") + public void testMethodToProtected2() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/increaseVisibility/invisibleFake/methodToProtected2.kt"); + doTest(fileName); + } + @TestMetadata("methodToPublic.kt") public void testMethodToPublic() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/increaseVisibility/invisibleFake/methodToPublic.kt"); @@ -6313,6 +6331,24 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { doTest(fileName); } + @TestMetadata("propertyToNotProtected.kt") + public void testPropertyToNotProtected() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/increaseVisibility/invisibleFake/propertyToNotProtected.kt"); + doTest(fileName); + } + + @TestMetadata("propertyToProtected.kt") + public void testPropertyToProtected() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/increaseVisibility/invisibleFake/propertyToProtected.kt"); + doTest(fileName); + } + + @TestMetadata("propertyToProtected2.kt") + public void testPropertyToProtected2() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/increaseVisibility/invisibleFake/propertyToProtected2.kt"); + doTest(fileName); + } + @TestMetadata("propertyToPublic.kt") public void testPropertyToPublic() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/increaseVisibility/invisibleFake/propertyToPublic.kt");