diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/IncreaseVisibilityFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/IncreaseVisibilityFix.kt index 70dc1e7008f..27b0437ca68 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/IncreaseVisibilityFix.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/IncreaseVisibilityFix.kt @@ -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(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(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) } } } diff --git a/idea/testData/quickfix/increaseVisibility/privateMemberToInternalMultiFile.after.Dependency.kt b/idea/testData/quickfix/increaseVisibility/privateMemberToInternalMultiFile.after.Dependency.kt new file mode 100644 index 00000000000..fc5e12c2995 --- /dev/null +++ b/idea/testData/quickfix/increaseVisibility/privateMemberToInternalMultiFile.after.Dependency.kt @@ -0,0 +1,5 @@ +package test + +class First { + internal fun foo() = 42 +} diff --git a/idea/testData/quickfix/increaseVisibility/privateMemberToInternalMultiFile.after.kt b/idea/testData/quickfix/increaseVisibility/privateMemberToInternalMultiFile.after.kt new file mode 100644 index 00000000000..142af7a18ea --- /dev/null +++ b/idea/testData/quickfix/increaseVisibility/privateMemberToInternalMultiFile.after.kt @@ -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.foo() +} diff --git a/idea/testData/quickfix/increaseVisibility/privateMemberToInternalMultiFile.before.Dependency.kt b/idea/testData/quickfix/increaseVisibility/privateMemberToInternalMultiFile.before.Dependency.kt new file mode 100644 index 00000000000..e2be463877c --- /dev/null +++ b/idea/testData/quickfix/increaseVisibility/privateMemberToInternalMultiFile.before.Dependency.kt @@ -0,0 +1,5 @@ +package test + +class First { + private fun foo() = 42 +} diff --git a/idea/testData/quickfix/increaseVisibility/privateMemberToInternalMultiFile.before.Main.kt b/idea/testData/quickfix/increaseVisibility/privateMemberToInternalMultiFile.before.Main.kt new file mode 100644 index 00000000000..142af7a18ea --- /dev/null +++ b/idea/testData/quickfix/increaseVisibility/privateMemberToInternalMultiFile.before.Main.kt @@ -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.foo() +} diff --git a/idea/testData/quickfix/increaseVisibility/privateMemberToInternalSingleFile.kt b/idea/testData/quickfix/increaseVisibility/privateMemberToInternalSingleFile.kt new file mode 100644 index 00000000000..b879f122e31 --- /dev/null +++ b/idea/testData/quickfix/increaseVisibility/privateMemberToInternalSingleFile.kt @@ -0,0 +1,6 @@ +// "Make x internal" "true" +class First(private val x: Int) + +class Second(f: First) { + val y = f.x +} diff --git a/idea/testData/quickfix/increaseVisibility/privateMemberToInternalSingleFile.kt.after b/idea/testData/quickfix/increaseVisibility/privateMemberToInternalSingleFile.kt.after new file mode 100644 index 00000000000..09e85dd52a2 --- /dev/null +++ b/idea/testData/quickfix/increaseVisibility/privateMemberToInternalSingleFile.kt.after @@ -0,0 +1,6 @@ +// "Make x internal" "true" +class First(internal val x: Int) + +class Second(f: First) { + val y = f.x +} diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java index 971b082694d..1cb6b2e2641 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java @@ -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"); diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java index e95e153f33b..02a15559810 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java @@ -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)