KT-11806: increase visibility quick fix, private --> internal, also for members

This commit is contained in:
Mikhail Glukhikh
2016-04-08 16:22:33 +03:00
parent 2098bed86d
commit f12a9b7b95
9 changed files with 84 additions and 10 deletions
@@ -24,32 +24,47 @@ 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.lexer.KtModifierKeywordToken
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtModifierListOwner
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
class IncreaseVisibilityFix(element: KtModifierListOwner, private val elementName: String) :
KotlinQuickFixAction<KtModifierListOwner>(element), CleanupFix {
override fun getText() = "Make $elementName internal"
override fun getFamilyName() = "Make top-level declaration internal"
class IncreaseVisibilityFix(
element: KtModifierListOwner,
private val elementName: String,
private val visibilityModifier: KtModifierKeywordToken
) : KotlinQuickFixAction<KtModifierListOwner>(element), CleanupFix {
override fun getText() = "Make $elementName $visibilityModifier"
override fun getFamilyName() = "Make $visibilityModifier"
override fun invoke(project: Project, editor: Editor?, file: KtFile) {
element.addModifier(KtTokens.INTERNAL_KEYWORD)
element.addModifier(visibilityModifier)
}
companion object : KotlinSingleIntentionActionFactory() {
override fun createAction(diagnostic: Diagnostic): IntentionAction? {
val element = diagnostic.psiElement as? KtElement ?: return null
val context = element.analyze(BodyResolveMode.PARTIAL)
val usageModule = context.get(BindingContext.FILE_TO_PACKAGE_FRAGMENT, element.getContainingKtFile())?.module
?: return null
@Suppress("UNCHECKED_CAST")
val factory = diagnostic.factory as DiagnosticFactory3<*, DeclarationDescriptor, *, DeclarationDescriptor>
val descriptor = factory.cast(diagnostic).c
if (!DescriptorUtils.isTopLevelDeclaration(descriptor) ||
descriptor !is DeclarationDescriptorWithVisibility ||
descriptor.visibility != Visibilities.PRIVATE) return null
val descriptor = factory.cast(diagnostic).c as? DeclarationDescriptorWithVisibility ?: return null
val module = DescriptorUtils.getContainingModule(descriptor)
if (module != usageModule) return null
val declaration = DescriptorToSourceUtils.getSourceFromDescriptor(descriptor) as? KtModifierListOwner ?: return null
return IncreaseVisibilityFix(declaration, descriptor.name.asString())
if (descriptor.visibility != Visibilities.PRIVATE) return null
return IncreaseVisibilityFix(declaration, descriptor.name.asString(), KtTokens.INTERNAL_KEYWORD)
}
}
}
@@ -0,0 +1,5 @@
package test
class First {
internal fun foo() = 42
}
@@ -0,0 +1,8 @@
// "Make foo internal" "true"
// ERROR: Cannot access 'foo': it is 'private' in 'First'
package test
class Second(val f: First) {
fun bar() = f.<caret>foo()
}
@@ -0,0 +1,5 @@
package test
class First {
private fun foo() = 42
}
@@ -0,0 +1,8 @@
// "Make foo internal" "true"
// ERROR: Cannot access 'foo': it is 'private' in 'First'
package test
class Second(val f: First) {
fun bar() = f.<caret>foo()
}
@@ -0,0 +1,6 @@
// "Make x internal" "true"
class First(private val x: Int)
class Second(f: First) {
val y = f.<caret>x
}
@@ -0,0 +1,6 @@
// "Make x internal" "true"
class First(internal val x: Int)
class Second(f: First) {
val y = f.x
}
@@ -1294,6 +1294,12 @@ public class QuickFixMultiFileTestGenerated extends AbstractQuickFixMultiFileTes
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/increaseVisibility"), Pattern.compile("^(\\w+)\\.((before\\.Main\\.\\w+)|(test))$"), true);
}
@TestMetadata("privateMemberToInternalMultiFile.before.Main.kt")
public void testPrivateMemberToInternalMultiFile() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/increaseVisibility/privateMemberToInternalMultiFile.before.Main.kt");
doTestWithExtraFile(fileName);
}
@TestMetadata("privateTopLevelFunInFile.before.Main.kt")
public void testPrivateTopLevelFunInFile() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/increaseVisibility/privateTopLevelFunInFile.before.Main.kt");
@@ -4711,6 +4711,21 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
}
}
@TestMetadata("idea/testData/quickfix/increaseVisibility")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class IncreaseVisibility extends AbstractQuickFixTest {
public void testAllFilesPresentInIncreaseVisibility() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/increaseVisibility"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), true);
}
@TestMetadata("privateMemberToInternalSingleFile.kt")
public void testPrivateMemberToInternalSingleFile() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/increaseVisibility/privateMemberToInternalSingleFile.kt");
doTest(fileName);
}
}
@TestMetadata("idea/testData/quickfix/initializeWithConstructorParameter")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)