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 dc6a16fdfa4..329980701c0 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/expectactual/CreateExpectedFix.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/expectactual/CreateExpectedFix.kt @@ -16,6 +16,7 @@ import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.diagnostics.Diagnostic import org.jetbrains.kotlin.diagnostics.DiagnosticFactory import org.jetbrains.kotlin.diagnostics.Errors +import org.jetbrains.kotlin.idea.caches.project.implementedDescriptors import org.jetbrains.kotlin.idea.caches.project.implementedModules import org.jetbrains.kotlin.idea.caches.resolve.analyzeWithContent import org.jetbrains.kotlin.idea.core.ShortenReferences @@ -23,15 +24,24 @@ import org.jetbrains.kotlin.idea.core.overrideImplement.* import org.jetbrains.kotlin.idea.core.toDescriptor import org.jetbrains.kotlin.idea.quickfix.KotlinIntentionActionsFactory import org.jetbrains.kotlin.idea.quickfix.KotlinQuickFixAction +import org.jetbrains.kotlin.idea.refactoring.introduce.showErrorHint import org.jetbrains.kotlin.idea.util.application.executeWriteCommand +import org.jetbrains.kotlin.idea.util.hasDeclarationOf import org.jetbrains.kotlin.idea.util.liftToExpected import org.jetbrains.kotlin.idea.util.module +import org.jetbrains.kotlin.js.descriptorUtils.getJetTypeFqName import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject import org.jetbrains.kotlin.psi.psiUtil.createSmartPointer import org.jetbrains.kotlin.psi.psiUtil.hasActualModifier import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.MultiTargetPlatform +import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe +import org.jetbrains.kotlin.resolve.descriptorUtil.module +import org.jetbrains.kotlin.resolve.getMultiTargetPlatform +import org.jetbrains.kotlin.types.AbbreviatedType +import org.jetbrains.kotlin.types.KotlinType sealed class CreateExpectedFix( declaration: D, @@ -57,7 +67,14 @@ sealed class CreateExpectedFix( val targetExpectedClass = targetExpectedClassPointer?.element val expectedFile = targetExpectedClass?.containingKtFile ?: getOrCreateImplementationFile() ?: return DumbService.getInstance(project).runWhenSmart { - val generated = factory.generateIt(project, element) ?: return@runWhenSmart + val generated = try { + factory.generateIt(project, element) ?: return@runWhenSmart + } catch (e: KotlinTypeInaccessibleException) { + if (editor != null) { + showErrorHint(project, editor, "Cannot generate expected $elementType: " + e.message, e.message) + } + return@runWhenSmart + } project.executeWriteCommand("Create expected declaration") { if (expectedFile.packageDirective?.fqName != file.packageDirective?.fqName && @@ -129,7 +146,7 @@ class CreateExpectedClassFix( outerExpectedClass: KtClassOrObject?, commonModule: Module ) : CreateExpectedFix(klass, outerExpectedClass, commonModule, { project, element -> - generateClassOrObjectByActualClass(project, element, isNested = outerExpectedClass != null) + generateClassOrObjectByActualClass(project, element, listOfNotNull(outerExpectedClass)) }) { override val elementType = element.getTypeDescription() @@ -141,7 +158,7 @@ class CreateExpectedPropertyFix( commonModule: Module ) : CreateExpectedFix(property, targetExpectedClass, commonModule, { project, element -> val descriptor = element.toDescriptor() as? PropertyDescriptor - descriptor?.let { generateProperty(project, element, descriptor, targetExpectedClass) } + descriptor?.let { generateProperty(project, element, descriptor, targetExpectedClass, emptyList()) } }) { override val elementType = "property" @@ -153,7 +170,7 @@ class CreateExpectedFunctionFix( commonModule: Module ) : CreateExpectedFix(function, targetExpectedClass, commonModule, { project, element -> val descriptor = element.toDescriptor() as? FunctionDescriptor - descriptor?.let { generateFunction(project, element, descriptor, targetExpectedClass) } + descriptor?.let { generateFunction(project, element, descriptor, targetExpectedClass, emptyList()) } }) { override val elementType = "function" @@ -162,7 +179,7 @@ class CreateExpectedFunctionFix( private fun KtPsiFactory.generateClassOrObjectByActualClass( project: Project, actualClass: KtClassOrObject, - isNested: Boolean + outerExpectedClasses: List ): KtClassOrObject { val expectedClass = createClassCopyByText(actualClass) expectedClass.declarations.forEach { @@ -183,7 +200,7 @@ private fun KtPsiFactory.generateClassOrObjectByActualClass( expectedEntry.replace(createSuperTypeEntry(expectedEntry.typeReference!!.text)) } } - if (!isNested) { + if (outerExpectedClasses.isEmpty()) { expectedClass.addModifier(KtTokens.EXPECT_KEYWORD) } else { expectedClass.makeNotActual() @@ -195,15 +212,17 @@ private fun KtPsiFactory.generateClassOrObjectByActualClass( val expectedDeclaration: KtDeclaration = when (actualDeclaration) { is KtClassOrObject -> if (actualDeclaration !is KtEnumEntry) { - generateClassOrObjectByActualClass(project, actualDeclaration, isNested = true) + generateClassOrObjectByActualClass(project, actualDeclaration, outerExpectedClasses + expectedClass) } else { continue@declLoop } is KtCallableDeclaration -> { if (!actualDeclaration.hasActualModifier()) continue@declLoop when (actualDeclaration) { - is KtFunction -> generateFunction(project, actualDeclaration, descriptor as FunctionDescriptor, expectedClass) - is KtProperty -> generateProperty(project, actualDeclaration, descriptor as PropertyDescriptor, expectedClass) + is KtFunction -> + generateFunction(project, actualDeclaration, descriptor as FunctionDescriptor, expectedClass, outerExpectedClasses) + is KtProperty -> + generateProperty(project, actualDeclaration, descriptor as PropertyDescriptor, expectedClass, outerExpectedClasses) else -> continue@declLoop } } @@ -215,7 +234,8 @@ private fun KtPsiFactory.generateClassOrObjectByActualClass( for (actualProperty in actualClass.primaryConstructorParameters) { if (!actualProperty.hasValOrVar() || !actualProperty.hasActualModifier()) continue val descriptor = actualProperty.toDescriptor() as? PropertyDescriptor ?: continue - val expectedProperty = generateProperty(project, actualProperty, descriptor, expectedClass) + val expectedProperty = + generateProperty(project, actualProperty, descriptor, expectedClass, outerExpectedClasses) expectedClass.addDeclaration(expectedProperty) } } @@ -223,7 +243,8 @@ private fun KtPsiFactory.generateClassOrObjectByActualClass( if (expectedClass is KtClass && actualPrimaryConstructor != null) { val descriptor = actualPrimaryConstructor.toDescriptor() if (descriptor is FunctionDescriptor) { - val expectedPrimaryConstructor = generateFunction(project, actualPrimaryConstructor, descriptor, expectedClass) + val expectedPrimaryConstructor = + generateFunction(project, actualPrimaryConstructor, descriptor, expectedClass, outerExpectedClasses) expectedClass.createPrimaryConstructorIfAbsent().replace(expectedPrimaryConstructor) } } @@ -235,8 +256,15 @@ private fun generateFunction( project: Project, actualFunction: KtFunction, descriptor: FunctionDescriptor, - targetClass: KtClassOrObject? = null + targetClass: KtClassOrObject?, + outerExpectedClasses: List ): KtFunction { + val accessibleClasses = outerExpectedClasses + listOfNotNull(targetClass) + descriptor.checkTypeParameterBoundsAccessibility(accessibleClasses) + descriptor.returnType?.checkAccessibility(accessibleClasses) + descriptor.valueParameters.forEach { + it.type.checkAccessibility(accessibleClasses) + } val memberChooserObject = OverrideMemberChooserObject.create( actualFunction, descriptor, descriptor, OverrideMemberChooserObject.BodyType.NO_BODY @@ -252,8 +280,12 @@ private fun generateProperty( project: Project, actualProperty: KtNamedDeclaration, descriptor: PropertyDescriptor, - targetClass: KtClassOrObject? = null + targetClass: KtClassOrObject?, + outerExpectedClasses: List ): KtProperty { + val accessibleClasses = outerExpectedClasses + listOfNotNull(targetClass) + descriptor.checkTypeParameterBoundsAccessibility(accessibleClasses) + descriptor.type.checkAccessibility(accessibleClasses) val memberChooserObject = OverrideMemberChooserObject.create( actualProperty, descriptor, descriptor, OverrideMemberChooserObject.BodyType.NO_BODY @@ -265,6 +297,47 @@ private fun generateProperty( } as KtProperty } +private fun CallableMemberDescriptor.checkTypeParameterBoundsAccessibility(accessibleClasses: List) { + typeParameters.forEach { typeParameter -> + typeParameter.upperBounds.forEach { upperBound -> + upperBound.checkAccessibility(accessibleClasses) + } + } +} +private fun KotlinType.checkAccessibility(accessibleClasses: List) { + for (argument in arguments) { + if (argument.isStarProjection) continue + argument.type.checkAccessibility(accessibleClasses) + } + val classifierDescriptor = constructor.declarationDescriptor as? ClassifierDescriptorWithTypeParameters ?: return + val moduleDescriptor = classifierDescriptor.module + if (moduleDescriptor.getMultiTargetPlatform() == MultiTargetPlatform.Common) { + // Common classes are Ok + return + } + val implementedDescriptors = moduleDescriptor.implementedDescriptors + if (implementedDescriptors.isEmpty()) { + // This happens now if we are not in sources, in this case yet we cannot answer question about accessibility + // Very rude check about JDK classes + if (!classifierDescriptor.fqNameSafe.toString().startsWith("java.")) return + } + if (implementedDescriptors.any { it.hasDeclarationOf(classifierDescriptor) }) { + // Platform classes with expected class are also Ok + return + } + accessibleClasses.forEach { + if (classifierDescriptor.name == it.nameAsName) return + } + if (this is AbbreviatedType) { + // For type aliases without expected class, check expansions instead + expandedType.checkAccessibility(accessibleClasses) + } else { + throw KotlinTypeInaccessibleException(this) + } +} - +class KotlinTypeInaccessibleException(val type: KotlinType) : Exception() { + override val message: String + get() = "Type ${type.getJetTypeFqName(true)} is not accessible from common code" +} \ No newline at end of file diff --git a/idea/testData/multiModuleQuickFix/expectCompanion/common/Some.kt.after b/idea/testData/multiModuleQuickFix/expectCompanion/common/Some.kt.after new file mode 100644 index 00000000000..00e8fcc96af --- /dev/null +++ b/idea/testData/multiModuleQuickFix/expectCompanion/common/Some.kt.after @@ -0,0 +1,5 @@ +expect class Some { + companion object { + fun createMe(): Some + } +} \ No newline at end of file diff --git a/idea/testData/multiModuleQuickFix/expectCompanion/jvm/Some.kt b/idea/testData/multiModuleQuickFix/expectCompanion/jvm/Some.kt new file mode 100644 index 00000000000..e7457c1afb4 --- /dev/null +++ b/idea/testData/multiModuleQuickFix/expectCompanion/jvm/Some.kt @@ -0,0 +1,8 @@ +// "Create expected class in common module testModule_Common" "true" +// DISABLE-ERRORS + +actual class Some { + actual companion object { + actual fun createMe() = Some() + } +} \ No newline at end of file diff --git a/idea/testData/multiModuleQuickFix/expectCompanion/jvm/Some.kt.after b/idea/testData/multiModuleQuickFix/expectCompanion/jvm/Some.kt.after new file mode 100644 index 00000000000..e7457c1afb4 --- /dev/null +++ b/idea/testData/multiModuleQuickFix/expectCompanion/jvm/Some.kt.after @@ -0,0 +1,8 @@ +// "Create expected class in common module testModule_Common" "true" +// DISABLE-ERRORS + +actual class Some { + actual companion object { + actual fun createMe() = Some() + } +} \ No newline at end of file diff --git a/idea/testData/multiModuleQuickFix/expectFunWithAccessibleAlias/common/foo.kt b/idea/testData/multiModuleQuickFix/expectFunWithAccessibleAlias/common/foo.kt new file mode 100644 index 00000000000..9e9aff75dd4 --- /dev/null +++ b/idea/testData/multiModuleQuickFix/expectFunWithAccessibleAlias/common/foo.kt @@ -0,0 +1,2 @@ +expect class SomeString +// It would be great to have SomeString in foo() below, but it's problematic \ No newline at end of file diff --git a/idea/testData/multiModuleQuickFix/expectFunWithAccessibleAlias/common/foo.kt.after b/idea/testData/multiModuleQuickFix/expectFunWithAccessibleAlias/common/foo.kt.after new file mode 100644 index 00000000000..119431502d6 --- /dev/null +++ b/idea/testData/multiModuleQuickFix/expectFunWithAccessibleAlias/common/foo.kt.after @@ -0,0 +1,3 @@ +expect class SomeString +// It would be great to have SomeString in foo() below, but it's problematic +expect fun foo(): String \ No newline at end of file diff --git a/idea/testData/multiModuleQuickFix/expectFunWithAccessibleAlias/jvm/Utils.kt b/idea/testData/multiModuleQuickFix/expectFunWithAccessibleAlias/jvm/Utils.kt new file mode 100644 index 00000000000..23fd985d2f2 --- /dev/null +++ b/idea/testData/multiModuleQuickFix/expectFunWithAccessibleAlias/jvm/Utils.kt @@ -0,0 +1,6 @@ +// "Create expected function in common module testModule_Common" "true" +// DISABLE-ERRORS + +actual typealias SomeString = String + +actual fun foo(): SomeString = "" \ No newline at end of file diff --git a/idea/testData/multiModuleQuickFix/expectFunWithAccessibleAlias/jvm/Utils.kt.after b/idea/testData/multiModuleQuickFix/expectFunWithAccessibleAlias/jvm/Utils.kt.after new file mode 100644 index 00000000000..f2da9891ba2 --- /dev/null +++ b/idea/testData/multiModuleQuickFix/expectFunWithAccessibleAlias/jvm/Utils.kt.after @@ -0,0 +1,6 @@ +// "Create expected function in common module testModule_Common" "true" +// DISABLE-ERRORS + +actual typealias SomeString = String + +actual fun foo(): SomeString = "" \ No newline at end of file diff --git a/idea/testData/multiModuleQuickFix/expectFunWithAccessibleExpansion/common/foo.kt.after b/idea/testData/multiModuleQuickFix/expectFunWithAccessibleExpansion/common/foo.kt.after new file mode 100644 index 00000000000..cd4a44fceef --- /dev/null +++ b/idea/testData/multiModuleQuickFix/expectFunWithAccessibleExpansion/common/foo.kt.after @@ -0,0 +1 @@ +expect fun foo(): String \ No newline at end of file diff --git a/idea/testData/multiModuleQuickFix/expectFunWithAccessibleExpansion/jvm/Utils.kt b/idea/testData/multiModuleQuickFix/expectFunWithAccessibleExpansion/jvm/Utils.kt new file mode 100644 index 00000000000..b4ebde8295b --- /dev/null +++ b/idea/testData/multiModuleQuickFix/expectFunWithAccessibleExpansion/jvm/Utils.kt @@ -0,0 +1,6 @@ +// "Create expected function in common module testModule_Common" "true" +// DISABLE-ERRORS + +typealias SomeString = String + +actual fun foo(): SomeString = "" \ No newline at end of file diff --git a/idea/testData/multiModuleQuickFix/expectFunWithAccessibleExpansion/jvm/Utils.kt.after b/idea/testData/multiModuleQuickFix/expectFunWithAccessibleExpansion/jvm/Utils.kt.after new file mode 100644 index 00000000000..b1af2275ed1 --- /dev/null +++ b/idea/testData/multiModuleQuickFix/expectFunWithAccessibleExpansion/jvm/Utils.kt.after @@ -0,0 +1,6 @@ +// "Create expected function in common module testModule_Common" "true" +// DISABLE-ERRORS + +typealias SomeString = String + +actual fun foo(): SomeString = "" \ No newline at end of file diff --git a/idea/testData/multiModuleQuickFix/expectFunWithAccessibleParameter/common/foo.kt b/idea/testData/multiModuleQuickFix/expectFunWithAccessibleParameter/common/foo.kt new file mode 100644 index 00000000000..3913a9d8017 --- /dev/null +++ b/idea/testData/multiModuleQuickFix/expectFunWithAccessibleParameter/common/foo.kt @@ -0,0 +1 @@ +expect class Some \ No newline at end of file diff --git a/idea/testData/multiModuleQuickFix/expectFunWithAccessibleParameter/common/foo.kt.after b/idea/testData/multiModuleQuickFix/expectFunWithAccessibleParameter/common/foo.kt.after new file mode 100644 index 00000000000..6177f7a39a2 --- /dev/null +++ b/idea/testData/multiModuleQuickFix/expectFunWithAccessibleParameter/common/foo.kt.after @@ -0,0 +1,3 @@ +expect class Some + +expect fun foo(some: List) \ No newline at end of file diff --git a/idea/testData/multiModuleQuickFix/expectFunWithAccessibleParameter/jvm/Utils.kt b/idea/testData/multiModuleQuickFix/expectFunWithAccessibleParameter/jvm/Utils.kt new file mode 100644 index 00000000000..4a0bcb184f5 --- /dev/null +++ b/idea/testData/multiModuleQuickFix/expectFunWithAccessibleParameter/jvm/Utils.kt @@ -0,0 +1,6 @@ +// "Create expected function in common module testModule_Common" "true" +// DISABLE-ERRORS + +actual class Some + +actual fun foo(some: List) {} \ No newline at end of file diff --git a/idea/testData/multiModuleQuickFix/expectFunWithAccessibleParameter/jvm/Utils.kt.after b/idea/testData/multiModuleQuickFix/expectFunWithAccessibleParameter/jvm/Utils.kt.after new file mode 100644 index 00000000000..23fd0d2b2b1 --- /dev/null +++ b/idea/testData/multiModuleQuickFix/expectFunWithAccessibleParameter/jvm/Utils.kt.after @@ -0,0 +1,6 @@ +// "Create expected function in common module testModule_Common" "true" +// DISABLE-ERRORS + +actual class Some + +actual fun foo(some: List) {} \ No newline at end of file diff --git a/idea/testData/multiModuleQuickFix/expectFunWithInaccessibleBounds/common/foo.kt b/idea/testData/multiModuleQuickFix/expectFunWithInaccessibleBounds/common/foo.kt new file mode 100644 index 00000000000..7b13b86cdc0 --- /dev/null +++ b/idea/testData/multiModuleQuickFix/expectFunWithInaccessibleBounds/common/foo.kt @@ -0,0 +1 @@ +// To be implemented \ No newline at end of file diff --git a/idea/testData/multiModuleQuickFix/expectFunWithInaccessibleBounds/jvm/Utils.kt b/idea/testData/multiModuleQuickFix/expectFunWithInaccessibleBounds/jvm/Utils.kt new file mode 100644 index 00000000000..3c2ce98cce3 --- /dev/null +++ b/idea/testData/multiModuleQuickFix/expectFunWithInaccessibleBounds/jvm/Utils.kt @@ -0,0 +1,7 @@ +// "Create expected function in common module testModule_Common" "true" +// SHOULD_FAIL_WITH: Cannot generate expected function: Type Some is not accessible from common code +// DISABLE-ERRORS + +interface Some + +actual fun foo(some: List) {} \ No newline at end of file diff --git a/idea/testData/multiModuleQuickFix/expectFunWithInaccessibleBounds/jvm/Utils.kt.after b/idea/testData/multiModuleQuickFix/expectFunWithInaccessibleBounds/jvm/Utils.kt.after new file mode 100644 index 00000000000..3a1e543d6b0 --- /dev/null +++ b/idea/testData/multiModuleQuickFix/expectFunWithInaccessibleBounds/jvm/Utils.kt.after @@ -0,0 +1,7 @@ +// "Create expected function in common module testModule_Common" "true" +// SHOULD_FAIL_WITH: Cannot generate expected function: Type Some is not accessible from common code +// DISABLE-ERRORS + +interface Some + +actual fun foo(some: List) {} \ No newline at end of file diff --git a/idea/testData/multiModuleQuickFix/expectFunWithInaccessibleParameter/common/foo.kt b/idea/testData/multiModuleQuickFix/expectFunWithInaccessibleParameter/common/foo.kt new file mode 100644 index 00000000000..7b13b86cdc0 --- /dev/null +++ b/idea/testData/multiModuleQuickFix/expectFunWithInaccessibleParameter/common/foo.kt @@ -0,0 +1 @@ +// To be implemented \ No newline at end of file diff --git a/idea/testData/multiModuleQuickFix/expectFunWithInaccessibleParameter/jvm/Utils.kt b/idea/testData/multiModuleQuickFix/expectFunWithInaccessibleParameter/jvm/Utils.kt new file mode 100644 index 00000000000..7a808a29309 --- /dev/null +++ b/idea/testData/multiModuleQuickFix/expectFunWithInaccessibleParameter/jvm/Utils.kt @@ -0,0 +1,7 @@ +// "Create expected function in common module testModule_Common" "true" +// SHOULD_FAIL_WITH: Cannot generate expected function: Type Some is not accessible from common code +// DISABLE-ERRORS + +class Some + +actual fun foo(some: Some) {} \ No newline at end of file diff --git a/idea/testData/multiModuleQuickFix/expectFunWithInaccessibleParameter/jvm/Utils.kt.after b/idea/testData/multiModuleQuickFix/expectFunWithInaccessibleParameter/jvm/Utils.kt.after new file mode 100644 index 00000000000..4b4efd2a5a9 --- /dev/null +++ b/idea/testData/multiModuleQuickFix/expectFunWithInaccessibleParameter/jvm/Utils.kt.after @@ -0,0 +1,7 @@ +// "Create expected function in common module testModule_Common" "true" +// SHOULD_FAIL_WITH: Cannot generate expected function: Type Some is not accessible from common code +// DISABLE-ERRORS + +class Some + +actual fun foo(some: Some) {} \ No newline at end of file diff --git a/idea/testData/multiModuleQuickFix/expectFunWithInaccessibleTypeParameter/common/foo.kt b/idea/testData/multiModuleQuickFix/expectFunWithInaccessibleTypeParameter/common/foo.kt new file mode 100644 index 00000000000..7b13b86cdc0 --- /dev/null +++ b/idea/testData/multiModuleQuickFix/expectFunWithInaccessibleTypeParameter/common/foo.kt @@ -0,0 +1 @@ +// To be implemented \ No newline at end of file diff --git a/idea/testData/multiModuleQuickFix/expectFunWithInaccessibleTypeParameter/jvm/Utils.kt b/idea/testData/multiModuleQuickFix/expectFunWithInaccessibleTypeParameter/jvm/Utils.kt new file mode 100644 index 00000000000..e2e1aa0c169 --- /dev/null +++ b/idea/testData/multiModuleQuickFix/expectFunWithInaccessibleTypeParameter/jvm/Utils.kt @@ -0,0 +1,7 @@ +// "Create expected function in common module testModule_Common" "true" +// SHOULD_FAIL_WITH: Cannot generate expected function: Type Some is not accessible from common code +// DISABLE-ERRORS + +class Some + +actual fun foo(some: List) {} \ No newline at end of file diff --git a/idea/testData/multiModuleQuickFix/expectFunWithInaccessibleTypeParameter/jvm/Utils.kt.after b/idea/testData/multiModuleQuickFix/expectFunWithInaccessibleTypeParameter/jvm/Utils.kt.after new file mode 100644 index 00000000000..d7b843e6eb9 --- /dev/null +++ b/idea/testData/multiModuleQuickFix/expectFunWithInaccessibleTypeParameter/jvm/Utils.kt.after @@ -0,0 +1,7 @@ +// "Create expected function in common module testModule_Common" "true" +// SHOULD_FAIL_WITH: Cannot generate expected function: Type Some is not accessible from common code +// DISABLE-ERRORS + +class Some + +actual fun foo(some: List) {} \ No newline at end of file diff --git a/idea/testData/multiModuleQuickFix/expectFunWithJdk/proj_jvm_dep(fulljdk)/Utils.kt b/idea/testData/multiModuleQuickFix/expectFunWithJdk/proj_jvm_dep(fulljdk)/Utils.kt index ff1bf65c291..ece31a9c4e3 100644 --- a/idea/testData/multiModuleQuickFix/expectFunWithJdk/proj_jvm_dep(fulljdk)/Utils.kt +++ b/idea/testData/multiModuleQuickFix/expectFunWithJdk/proj_jvm_dep(fulljdk)/Utils.kt @@ -1,4 +1,5 @@ // "Create expected function in common module proj_Common" "true" +// SHOULD_FAIL_WITH: Cannot generate expected function: Type java.util.ArrayList is not accessible from common code // DISABLE-ERRORS import java.util.ArrayList diff --git a/idea/testData/multiModuleQuickFix/expectFunWithJdk/proj_jvm_dep(fulljdk)/Utils.kt.after b/idea/testData/multiModuleQuickFix/expectFunWithJdk/proj_jvm_dep(fulljdk)/Utils.kt.after index bec2d9aafc8..aef12b481c8 100644 --- a/idea/testData/multiModuleQuickFix/expectFunWithJdk/proj_jvm_dep(fulljdk)/Utils.kt.after +++ b/idea/testData/multiModuleQuickFix/expectFunWithJdk/proj_jvm_dep(fulljdk)/Utils.kt.after @@ -1,4 +1,5 @@ // "Create expected function in common module proj_Common" "true" +// SHOULD_FAIL_WITH: Cannot generate expected function: Type java.util.ArrayList is not accessible from common code // DISABLE-ERRORS import java.util.ArrayList diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/AbstractQuickFixMultiModuleTest.kt b/idea/tests/org/jetbrains/kotlin/idea/quickfix/AbstractQuickFixMultiModuleTest.kt index b2d995cd76a..1d50d440b5e 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/AbstractQuickFixMultiModuleTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/AbstractQuickFixMultiModuleTest.kt @@ -9,6 +9,7 @@ import com.intellij.codeInsight.daemon.quickFix.ActionHint import com.intellij.codeInsight.daemon.quickFix.LightQuickFixTestCase import com.intellij.codeInsight.intention.IntentionAction import com.intellij.openapi.command.CommandProcessor +import com.intellij.testFramework.UsefulTestCase import junit.framework.ComparisonFailure import junit.framework.TestCase import org.jetbrains.kotlin.idea.inspections.findExistingEditor @@ -21,6 +22,7 @@ import org.jetbrains.kotlin.idea.test.findFileWithCaret import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.test.InTextDirectivesUtils import org.jetbrains.kotlin.test.KotlinTestUtils +import org.junit.Assert import java.io.File abstract class AbstractQuickFixMultiModuleTest : AbstractMultiModuleTest(), QuickFixTest { @@ -42,6 +44,7 @@ abstract class AbstractQuickFixMultiModuleTest : AbstractMultiModuleTest(), Quic enableInspectionTools(*inspections) CommandProcessor.getInstance().executeCommand(project, { + var expectedErrorMessage: String = "" try { val actionHint = ActionHint.parse(actionFile, actionFileText) val text = actionHint.expectedText @@ -52,24 +55,28 @@ abstract class AbstractQuickFixMultiModuleTest : AbstractMultiModuleTest(), Quic DirectiveBasedActionUtils.checkForUnexpectedErrors(actionFile) } + expectedErrorMessage = InTextDirectivesUtils.findStringWithPrefixes(actionFileText, "// SHOULD_FAIL_WITH: ") ?: "" + AbstractQuickFixMultiFileTest.doAction( - text, file, editor, actionShouldBeAvailable, actionFileName, this::availableActions, this::doHighlighting, - InTextDirectivesUtils.isDirectiveDefined(actionFile.text, "// SHOULD_BE_AVAILABLE_AFTER_EXECUTION") + text, file, editor, actionShouldBeAvailable, actionFileName, this::availableActions, this::doHighlighting, + InTextDirectivesUtils.isDirectiveDefined(actionFile.text, "// SHOULD_BE_AVAILABLE_AFTER_EXECUTION") ) if (actionShouldBeAvailable) { compareToExpected() } - } - catch (e: ComparisonFailure) { + UsefulTestCase.assertEmpty(expectedErrorMessage) + } catch (e: ComparisonFailure) { throw e - } - catch (e: AssertionError) { + } catch (e: AssertionError) { throw e - } - catch (e: Throwable) { - e.printStackTrace() - TestCase.fail(getTestName(true)) + } catch (e: Throwable) { + if (expectedErrorMessage.isEmpty()) { + e.printStackTrace() + TestCase.fail(getTestName(true)) + } else { + Assert.assertEquals("Wrong exception message", expectedErrorMessage, e.message) + } } }, "", "") } diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiModuleTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiModuleTestGenerated.java index 3180b735e42..d838a5c3916 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiModuleTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiModuleTestGenerated.java @@ -294,6 +294,11 @@ public class QuickFixMultiModuleTestGenerated extends AbstractQuickFixMultiModul runTest("idea/testData/multiModuleQuickFix/expectClassWithSupertype/"); } + @TestMetadata("expectCompanion") + public void testExpectCompanion() throws Exception { + runTest("idea/testData/multiModuleQuickFix/expectCompanion/"); + } + @TestMetadata("expectDataClass") public void testExpectDataClass() throws Exception { runTest("idea/testData/multiModuleQuickFix/expectDataClass/"); @@ -309,6 +314,36 @@ public class QuickFixMultiModuleTestGenerated extends AbstractQuickFixMultiModul runTest("idea/testData/multiModuleQuickFix/expectEnumEmpty/"); } + @TestMetadata("expectFunWithAccessibleAlias") + public void testExpectFunWithAccessibleAlias() throws Exception { + runTest("idea/testData/multiModuleQuickFix/expectFunWithAccessibleAlias/"); + } + + @TestMetadata("expectFunWithAccessibleExpansion") + public void testExpectFunWithAccessibleExpansion() throws Exception { + runTest("idea/testData/multiModuleQuickFix/expectFunWithAccessibleExpansion/"); + } + + @TestMetadata("expectFunWithAccessibleParameter") + public void testExpectFunWithAccessibleParameter() throws Exception { + runTest("idea/testData/multiModuleQuickFix/expectFunWithAccessibleParameter/"); + } + + @TestMetadata("expectFunWithInaccessibleBounds") + public void testExpectFunWithInaccessibleBounds() throws Exception { + runTest("idea/testData/multiModuleQuickFix/expectFunWithInaccessibleBounds/"); + } + + @TestMetadata("expectFunWithInaccessibleParameter") + public void testExpectFunWithInaccessibleParameter() throws Exception { + runTest("idea/testData/multiModuleQuickFix/expectFunWithInaccessibleParameter/"); + } + + @TestMetadata("expectFunWithInaccessibleTypeParameter") + public void testExpectFunWithInaccessibleTypeParameter() throws Exception { + runTest("idea/testData/multiModuleQuickFix/expectFunWithInaccessibleTypeParameter/"); + } + @TestMetadata("expectFunWithJdk") public void testExpectFunWithJdk() throws Exception { runTest("idea/testData/multiModuleQuickFix/expectFunWithJdk/");