diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/expectactual/CreateExpectedFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/expectactual/CreateExpectedFix.kt index 89eb160ee8f..399f7f1e7b6 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/expectactual/CreateExpectedFix.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/expectactual/CreateExpectedFix.kt @@ -24,13 +24,10 @@ import org.jetbrains.kotlin.idea.core.overrideImplement.makeActual import org.jetbrains.kotlin.idea.core.overrideImplement.makeNotActual import org.jetbrains.kotlin.idea.core.toDescriptor import org.jetbrains.kotlin.idea.core.util.DescriptorMemberChooserObject -import org.jetbrains.kotlin.idea.inspections.findExistingEditor import org.jetbrains.kotlin.idea.quickfix.KotlinIntentionActionsFactory import org.jetbrains.kotlin.idea.quickfix.TypeAccessibilityChecker import org.jetbrains.kotlin.idea.refactoring.getExpressionShortText -import org.jetbrains.kotlin.idea.refactoring.introduce.showErrorHint import org.jetbrains.kotlin.idea.util.application.executeWriteCommand -import org.jetbrains.kotlin.idea.util.hasPrivateModifier import org.jetbrains.kotlin.idea.util.liftToExpected import org.jetbrains.kotlin.idea.util.module import org.jetbrains.kotlin.lexer.KtTokens @@ -118,16 +115,13 @@ class CreateExpectedClassFix( ) : CreateExpectedFix(klass, outerExpectedClass, commonModule, block@{ project, checker, element -> val originalElements = element.collectDeclarations(withSelf = false).toList() val existingClasses = checker.findAndApplyExistingClasses(originalElements + klass) - if (!checker.isCorrectAndHaveNonPrivateModifier(element)) { - showUnknownTypesError(element) - return@block null - } + if (!checker.isCorrectAndHaveNonPrivateModifier(element, true)) return@block null val (members, declarationsWithNonExistentClasses) = originalElements.partition { checker.isCorrectAndHaveNonPrivateModifier(it) } - if (!showUnknownTypesDialog(project, declarationsWithNonExistentClasses)) return@block null + if (!showUnknownTypeInDeclarationDialog(project, declarationsWithNonExistentClasses)) return@block null val membersForSelection = members.filter { !it.isAlwaysActual() && if (it is KtParameter) it.hasValOrVar() else true @@ -144,15 +138,12 @@ class CreateExpectedClassFix( val selectedClasses = checker.findAndApplyExistingClasses(selectedElements) val resultDeclarations = if (selectedClasses != existingClasses) { - if (!checker.isCorrectAndHaveNonPrivateModifier(element)) { - showUnknownTypesError(element) - return@block null - } + if (!checker.isCorrectAndHaveNonPrivateModifier(element, true)) return@block null val (resultDeclarations, withErrors) = selectedElements.partition { checker.isCorrectAndHaveNonPrivateModifier(it) } - if (!showUnknownTypesDialog(project, withErrors)) return@block null + if (!showUnknownTypeInDeclarationDialog(project, withErrors)) return@block null resultDeclarations } else selectedElements @@ -177,7 +168,10 @@ private fun TypeAccessibilityChecker.findAndApplyExistingClasses(elements: Colle } } -private fun showUnknownTypesDialog(project: Project, declarationsWithNonExistentClasses: Collection): Boolean { +private fun showUnknownTypeInDeclarationDialog( + project: Project, + declarationsWithNonExistentClasses: Collection +): Boolean { if (declarationsWithNonExistentClasses.isEmpty()) return true val message = escapeXml( declarationsWithNonExistentClasses.joinToString( @@ -195,17 +189,6 @@ private fun showUnknownTypesDialog(project: Project, declarationsWithNonExistent ) } -private fun showUnknownTypesError(element: KtNamedDeclaration) { - element.findExistingEditor()?.let { editor -> - showErrorHint( - element.project, - editor, - "You cannot create the expect declaration from:\n${escapeXml(getExpressionShortText(element))}", - "Unknown types" - ) - } -} - private fun KtDeclaration.canAddActualModifier() = when (this) { is KtEnumEntry, is KtClassInitializer -> false is KtParameter -> hasValOrVar() @@ -300,10 +283,7 @@ class CreateExpectedCallableMemberFix( targetExpectedClass: KtClassOrObject?, commonModule: Module ) : CreateExpectedFix(declaration, targetExpectedClass, commonModule, block@{ project, checker, element -> - if (!checker.isCorrectAndHaveNonPrivateModifier(element)) { - showUnknownTypesError(element) - return@block null - } + if (!checker.isCorrectAndHaveNonPrivateModifier(element, true)) return@block null val descriptor = element.toDescriptor() as? CallableMemberDescriptor checker.existingTypeNames = targetExpectedClass?.getSuperNames()?.toSet().orEmpty() descriptor?.let { @@ -317,6 +297,3 @@ class CreateExpectedCallableMemberFix( ) } }) - -private fun TypeAccessibilityChecker.isCorrectAndHaveNonPrivateModifier(declaration: KtNamedDeclaration): Boolean = - !declaration.hasPrivateModifier() && checkAccessibility(declaration) \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/expectactual/ExpectActualUtils.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/expectactual/ExpectActualUtils.kt index eef89ed2bfe..b3f972531b3 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/expectactual/ExpectActualUtils.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/expectactual/ExpectActualUtils.kt @@ -24,14 +24,13 @@ import org.jetbrains.kotlin.idea.core.overrideImplement.OverrideMemberChooserObj import org.jetbrains.kotlin.idea.core.overrideImplement.generateMember import org.jetbrains.kotlin.idea.core.overrideImplement.makeNotActual import org.jetbrains.kotlin.idea.core.toDescriptor +import org.jetbrains.kotlin.idea.inspections.findExistingEditor import org.jetbrains.kotlin.idea.quickfix.TypeAccessibilityChecker import org.jetbrains.kotlin.idea.refactoring.createKotlinFile import org.jetbrains.kotlin.idea.refactoring.fqName.fqName -import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers +import org.jetbrains.kotlin.idea.refactoring.introduce.showErrorHint +import org.jetbrains.kotlin.idea.util.* import org.jetbrains.kotlin.idea.util.application.runWriteAction -import org.jetbrains.kotlin.idea.util.hasInlineModifier -import org.jetbrains.kotlin.idea.util.isEffectivelyActual -import org.jetbrains.kotlin.idea.util.mustHaveValOrVar import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.psi.* @@ -379,3 +378,35 @@ class KotlinTypeInaccessibleException(fqNames: Collection) : Exception( fun KtNamedDeclaration.isAlwaysActual(): Boolean = safeAs()?.parent?.parent?.safeAs() ?.mustHaveValOrVar() ?: false + + +fun TypeAccessibilityChecker.isCorrectAndHaveNonPrivateModifier(declaration: KtNamedDeclaration, showErrorHint: Boolean = false): Boolean { + if (declaration.hasPrivateModifier()) { + if (showErrorHint) showInaccessibleDeclarationError(declaration, "The declaration has a private modifier") + return false + } + + if (!showErrorHint) return checkAccessibility(declaration) + + val types = incorrectTypes(declaration).ifEmpty { return true } + showInaccessibleDeclarationError( + declaration, + "Some types are not accessible from ${targetModule.name}:\n" + TypeAccessibilityChecker.typesToString( + types + ) + ) + + return false +} + +private fun showInaccessibleDeclarationError(element: KtNamedDeclaration, message: String) { + element.findExistingEditor()?.let { editor -> + showErrorHint(element.project, editor, message, "Inaccessible declaration") + } +} + +fun TypeAccessibilityChecker.Companion.typesToString(types: Collection, separator: CharSequence = "\n"): String { + return types.toSet().joinToString(separator = separator) { + it?.shortName()?.asString() ?: "Unknown type" + } +} \ No newline at end of file diff --git a/idea/testData/multiModuleQuickFix/accessibilityChecker/classUpperBounds/jvm/Utils.kt b/idea/testData/multiModuleQuickFix/accessibilityChecker/classUpperBounds/jvm/Utils.kt index 235a746c586..bd23a757dd8 100644 --- a/idea/testData/multiModuleQuickFix/accessibilityChecker/classUpperBounds/jvm/Utils.kt +++ b/idea/testData/multiModuleQuickFix/accessibilityChecker/classUpperBounds/jvm/Utils.kt @@ -1,5 +1,5 @@ // "Create expected class in common module testModule_Common" "true" -// SHOULD_FAIL_WITH: You cannot create the expect declaration from:,class A +// SHOULD_FAIL_WITH: Some types are not accessible from testModule_Common:,Some,A // DISABLE-ERRORS interface Some diff --git a/idea/testData/multiModuleQuickFix/accessibilityChecker/topLevelFunParameter/jvm/Utils.kt b/idea/testData/multiModuleQuickFix/accessibilityChecker/topLevelFunParameter/jvm/Utils.kt index 36c7d038a63..7698c13fca6 100644 --- a/idea/testData/multiModuleQuickFix/accessibilityChecker/topLevelFunParameter/jvm/Utils.kt +++ b/idea/testData/multiModuleQuickFix/accessibilityChecker/topLevelFunParameter/jvm/Utils.kt @@ -1,5 +1,5 @@ // "Create expected function in common module testModule_Common" "true" -// SHOULD_FAIL_WITH: You cannot create the expect declaration from:,fun foo(some: Some){...} +// SHOULD_FAIL_WITH: Some types are not accessible from testModule_Common:,Some // DISABLE-ERRORS class Some diff --git a/idea/testData/multiModuleQuickFix/accessibilityChecker/topLevelFunReturnType/jvm/Utils.kt b/idea/testData/multiModuleQuickFix/accessibilityChecker/topLevelFunReturnType/jvm/Utils.kt index a8d1586db64..acea7f1f1f2 100644 --- a/idea/testData/multiModuleQuickFix/accessibilityChecker/topLevelFunReturnType/jvm/Utils.kt +++ b/idea/testData/multiModuleQuickFix/accessibilityChecker/topLevelFunReturnType/jvm/Utils.kt @@ -1,5 +1,5 @@ // "Create expected function in common module testModule_Common" "true" -// SHOULD_FAIL_WITH: You cannot create the expect declaration from:,fun foo(some: List<T>) = TODO() +// SHOULD_FAIL_WITH: Some types are not accessible from testModule_Common:,Some // DISABLE-ERRORS interface Some diff --git a/idea/testData/multiModuleQuickFix/accessibilityChecker/topLevelFunTypeParameter/jvm/Utils.kt b/idea/testData/multiModuleQuickFix/accessibilityChecker/topLevelFunTypeParameter/jvm/Utils.kt index 4a606010797..31268d8b4f9 100644 --- a/idea/testData/multiModuleQuickFix/accessibilityChecker/topLevelFunTypeParameter/jvm/Utils.kt +++ b/idea/testData/multiModuleQuickFix/accessibilityChecker/topLevelFunTypeParameter/jvm/Utils.kt @@ -1,5 +1,5 @@ // "Create expected function in common module testModule_Common" "true" -// SHOULD_FAIL_WITH: You cannot create the expect declaration from:,fun foo(some: List<Some>){...} +// SHOULD_FAIL_WITH: Some types are not accessible from testModule_Common:,Some // DISABLE-ERRORS class Some diff --git a/idea/testData/multiModuleQuickFix/accessibilityChecker/topLevelFunUpperBounds/jvm/Utils.kt b/idea/testData/multiModuleQuickFix/accessibilityChecker/topLevelFunUpperBounds/jvm/Utils.kt index d709cd7a7a8..02272bc513e 100644 --- a/idea/testData/multiModuleQuickFix/accessibilityChecker/topLevelFunUpperBounds/jvm/Utils.kt +++ b/idea/testData/multiModuleQuickFix/accessibilityChecker/topLevelFunUpperBounds/jvm/Utils.kt @@ -1,5 +1,5 @@ // "Create expected function in common module testModule_Common" "true" -// SHOULD_FAIL_WITH: You cannot create the expect declaration from:,fun foo(some: List<T>){...} +// SHOULD_FAIL_WITH: Some types are not accessible from testModule_Common:,Some // DISABLE-ERRORS interface Some diff --git a/idea/testData/multiModuleQuickFix/accessibilityChecker/topLevelFunUpperBounds2/jvm/Utils.kt b/idea/testData/multiModuleQuickFix/accessibilityChecker/topLevelFunUpperBounds2/jvm/Utils.kt index 0e8fb14775d..72f10967042 100644 --- a/idea/testData/multiModuleQuickFix/accessibilityChecker/topLevelFunUpperBounds2/jvm/Utils.kt +++ b/idea/testData/multiModuleQuickFix/accessibilityChecker/topLevelFunUpperBounds2/jvm/Utils.kt @@ -1,5 +1,5 @@ // "Create expected function in common module testModule_Common" "true" -// SHOULD_FAIL_WITH: You cannot create the expect declaration from:,fun foo(some: List<T>){...} +// SHOULD_FAIL_WITH: Some types are not accessible from testModule_Common:,Some // DISABLE-ERRORS interface Some diff --git a/idea/testData/multiModuleQuickFix/accessibilityChecker/topLevelProperty/jvm/Utils.kt b/idea/testData/multiModuleQuickFix/accessibilityChecker/topLevelProperty/jvm/Utils.kt index 5c2eb96e052..cce2845127c 100644 --- a/idea/testData/multiModuleQuickFix/accessibilityChecker/topLevelProperty/jvm/Utils.kt +++ b/idea/testData/multiModuleQuickFix/accessibilityChecker/topLevelProperty/jvm/Utils.kt @@ -1,5 +1,5 @@ // "Create expected property in common module testModule_Common" "true" -// SHOULD_FAIL_WITH: You cannot create the expect declaration from:,actual val foo: Some = TODO() +// SHOULD_FAIL_WITH: Some types are not accessible from testModule_Common:,Some // DISABLE-ERRORS interface Some diff --git a/idea/testData/multiModuleQuickFix/accessibilityChecker/topLevelPropertyTypeParam2/jvm/Utils.kt b/idea/testData/multiModuleQuickFix/accessibilityChecker/topLevelPropertyTypeParam2/jvm/Utils.kt index 7624f7d0992..eb63734610f 100644 --- a/idea/testData/multiModuleQuickFix/accessibilityChecker/topLevelPropertyTypeParam2/jvm/Utils.kt +++ b/idea/testData/multiModuleQuickFix/accessibilityChecker/topLevelPropertyTypeParam2/jvm/Utils.kt @@ -1,5 +1,5 @@ // "Create expected property in common module testModule_Common" "true" -// SHOULD_FAIL_WITH: You cannot create the expect declaration from:,actual val <T>Some<T>.foo: Some<T> get() = TODO() +// SHOULD_FAIL_WITH: Some types are not accessible from testModule_Common:,Some // DISABLE-ERRORS class Some diff --git a/idea/testData/multiModuleQuickFix/accessibilityChecker/topLevelPropertyTypeParamBound/jvm/Utils.kt b/idea/testData/multiModuleQuickFix/accessibilityChecker/topLevelPropertyTypeParamBound/jvm/Utils.kt index 3929fea5923..c9bee640aa5 100644 --- a/idea/testData/multiModuleQuickFix/accessibilityChecker/topLevelPropertyTypeParamBound/jvm/Utils.kt +++ b/idea/testData/multiModuleQuickFix/accessibilityChecker/topLevelPropertyTypeParamBound/jvm/Utils.kt @@ -1,5 +1,5 @@ // "Create expected property in common module testModule_Common" "true" -// SHOULD_FAIL_WITH: You cannot create the expect declaration from:,actual val <T: A> Some<T>.foo: Some<T> get() = TODO() +// SHOULD_FAIL_WITH: Some types are not accessible from testModule_Common:,A // DISABLE-ERRORS interface A diff --git a/idea/testData/multiModuleQuickFix/createExpect/funWithAccessibleExpansion/jvm/Utils.kt b/idea/testData/multiModuleQuickFix/createExpect/funWithAccessibleExpansion/jvm/Utils.kt index 7911856021c..4ee479ff073 100644 --- a/idea/testData/multiModuleQuickFix/createExpect/funWithAccessibleExpansion/jvm/Utils.kt +++ b/idea/testData/multiModuleQuickFix/createExpect/funWithAccessibleExpansion/jvm/Utils.kt @@ -1,5 +1,5 @@ // "Create expected function in common module testModule_Common" "true" -// SHOULD_FAIL_WITH: You cannot create the expect declaration from:,fun foo() = "" +// SHOULD_FAIL_WITH: Some types are not accessible from testModule_Common:,SomeString // DISABLE-ERRORS typealias SomeString = String diff --git a/idea/testData/multiModuleQuickFix/createExpect/funWithJdk/proj_jvm_dep(fulljdk)/Utils.kt b/idea/testData/multiModuleQuickFix/createExpect/funWithJdk/proj_jvm_dep(fulljdk)/Utils.kt index e2cdf3b88c5..1c3e362d2cb 100644 --- a/idea/testData/multiModuleQuickFix/createExpect/funWithJdk/proj_jvm_dep(fulljdk)/Utils.kt +++ b/idea/testData/multiModuleQuickFix/createExpect/funWithJdk/proj_jvm_dep(fulljdk)/Utils.kt @@ -1,5 +1,5 @@ // "Create expected function in common module proj_Common" "true" -// SHOULD_FAIL_WITH: You cannot create the expect declaration from:,fun createList() = ArrayList() +// SHOULD_FAIL_WITH: Some types are not accessible from proj_Common:,ArrayList // DISABLE-ERRORS import java.util.ArrayList diff --git a/idea/testData/multiModuleQuickFix/createExpect/funWithJdk/proj_jvm_dep(fulljdk)/Utils.kt.after b/idea/testData/multiModuleQuickFix/createExpect/funWithJdk/proj_jvm_dep(fulljdk)/Utils.kt.after index 0c83faf39cb..f8391b4e8fc 100644 --- a/idea/testData/multiModuleQuickFix/createExpect/funWithJdk/proj_jvm_dep(fulljdk)/Utils.kt.after +++ b/idea/testData/multiModuleQuickFix/createExpect/funWithJdk/proj_jvm_dep(fulljdk)/Utils.kt.after @@ -1,5 +1,5 @@ // "Create expected function in common module proj_Common" "true" -// SHOULD_FAIL_WITH: You cannot create the expect declaration from:,fun createList() = ArrayList() +// SHOULD_FAIL_WITH: Some types are not accessible from proj_Common:,ArrayList // DISABLE-ERRORS import java.util.ArrayList