Offer to make INVISIBLE_MEMBER protected if referenced from subclass

So #KT-19614 Fixed
This commit is contained in:
Toshiaki Kameyama
2017-08-17 13:06:13 +03:00
committed by Mikhail Glukhikh
parent 0adf1d210f
commit f0f6a252a5
12 changed files with 176 additions and 2 deletions
@@ -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<IntentionAction> {
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)
}
@@ -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().<caret>doSth()
}
}
@@ -0,0 +1,12 @@
// "Make 'doSth' protected" "true"
open class A {
private fun doSth() {
}
}
class B : A() {
fun bar() {
<caret>doSth()
}
}
@@ -0,0 +1,12 @@
// "Make 'doSth' protected" "true"
open class A {
protected fun doSth() {
}
}
class B : A() {
fun bar() {
doSth()
}
}
@@ -0,0 +1,14 @@
// "Make 'doSth' protected" "true"
open class A {
private fun doSth() {
}
}
open class B : A()
class C : B() {
fun bar() {
<caret>doSth()
}
}
@@ -0,0 +1,14 @@
// "Make 'doSth' protected" "true"
open class A {
protected fun doSth() {
}
}
open class B : A()
class C : B() {
fun bar() {
doSth()
}
}
@@ -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().<caret>foo
}
}
@@ -0,0 +1,11 @@
// "Make 'foo' protected" "true"
open class A {
private val foo = 1
}
class B : A() {
fun bar() {
<caret>foo
}
}
@@ -0,0 +1,11 @@
// "Make 'foo' protected" "true"
open class A {
protected val foo = 1
}
class B : A() {
fun bar() {
foo
}
}
@@ -0,0 +1,13 @@
// "Make 'foo' protected" "true"
open class A {
private val foo = 1
}
open class B : A()
class C : B() {
fun bar() {
<caret>foo
}
}
@@ -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
}
}
@@ -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");