Create expected quick-fix: check types accessibility before creation
Related to KT-27075
This commit is contained in:
@@ -16,6 +16,7 @@ import org.jetbrains.kotlin.descriptors.*
|
|||||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||||
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory
|
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory
|
||||||
import org.jetbrains.kotlin.diagnostics.Errors
|
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.project.implementedModules
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyzeWithContent
|
import org.jetbrains.kotlin.idea.caches.resolve.analyzeWithContent
|
||||||
import org.jetbrains.kotlin.idea.core.ShortenReferences
|
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.core.toDescriptor
|
||||||
import org.jetbrains.kotlin.idea.quickfix.KotlinIntentionActionsFactory
|
import org.jetbrains.kotlin.idea.quickfix.KotlinIntentionActionsFactory
|
||||||
import org.jetbrains.kotlin.idea.quickfix.KotlinQuickFixAction
|
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.application.executeWriteCommand
|
||||||
|
import org.jetbrains.kotlin.idea.util.hasDeclarationOf
|
||||||
import org.jetbrains.kotlin.idea.util.liftToExpected
|
import org.jetbrains.kotlin.idea.util.liftToExpected
|
||||||
import org.jetbrains.kotlin.idea.util.module
|
import org.jetbrains.kotlin.idea.util.module
|
||||||
|
import org.jetbrains.kotlin.js.descriptorUtils.getJetTypeFqName
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
|
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.createSmartPointer
|
import org.jetbrains.kotlin.psi.psiUtil.createSmartPointer
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.hasActualModifier
|
import org.jetbrains.kotlin.psi.psiUtil.hasActualModifier
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
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<out D : KtNamedDeclaration>(
|
sealed class CreateExpectedFix<out D : KtNamedDeclaration>(
|
||||||
declaration: D,
|
declaration: D,
|
||||||
@@ -57,7 +67,14 @@ sealed class CreateExpectedFix<out D : KtNamedDeclaration>(
|
|||||||
val targetExpectedClass = targetExpectedClassPointer?.element
|
val targetExpectedClass = targetExpectedClassPointer?.element
|
||||||
val expectedFile = targetExpectedClass?.containingKtFile ?: getOrCreateImplementationFile() ?: return
|
val expectedFile = targetExpectedClass?.containingKtFile ?: getOrCreateImplementationFile() ?: return
|
||||||
DumbService.getInstance(project).runWhenSmart {
|
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") {
|
project.executeWriteCommand("Create expected declaration") {
|
||||||
if (expectedFile.packageDirective?.fqName != file.packageDirective?.fqName &&
|
if (expectedFile.packageDirective?.fqName != file.packageDirective?.fqName &&
|
||||||
@@ -129,7 +146,7 @@ class CreateExpectedClassFix(
|
|||||||
outerExpectedClass: KtClassOrObject?,
|
outerExpectedClass: KtClassOrObject?,
|
||||||
commonModule: Module
|
commonModule: Module
|
||||||
) : CreateExpectedFix<KtClassOrObject>(klass, outerExpectedClass, commonModule, { project, element ->
|
) : CreateExpectedFix<KtClassOrObject>(klass, outerExpectedClass, commonModule, { project, element ->
|
||||||
generateClassOrObjectByActualClass(project, element, isNested = outerExpectedClass != null)
|
generateClassOrObjectByActualClass(project, element, listOfNotNull(outerExpectedClass))
|
||||||
}) {
|
}) {
|
||||||
|
|
||||||
override val elementType = element.getTypeDescription()
|
override val elementType = element.getTypeDescription()
|
||||||
@@ -141,7 +158,7 @@ class CreateExpectedPropertyFix(
|
|||||||
commonModule: Module
|
commonModule: Module
|
||||||
) : CreateExpectedFix<KtNamedDeclaration>(property, targetExpectedClass, commonModule, { project, element ->
|
) : CreateExpectedFix<KtNamedDeclaration>(property, targetExpectedClass, commonModule, { project, element ->
|
||||||
val descriptor = element.toDescriptor() as? PropertyDescriptor
|
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"
|
override val elementType = "property"
|
||||||
@@ -153,7 +170,7 @@ class CreateExpectedFunctionFix(
|
|||||||
commonModule: Module
|
commonModule: Module
|
||||||
) : CreateExpectedFix<KtFunction>(function, targetExpectedClass, commonModule, { project, element ->
|
) : CreateExpectedFix<KtFunction>(function, targetExpectedClass, commonModule, { project, element ->
|
||||||
val descriptor = element.toDescriptor() as? FunctionDescriptor
|
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"
|
override val elementType = "function"
|
||||||
@@ -162,7 +179,7 @@ class CreateExpectedFunctionFix(
|
|||||||
private fun KtPsiFactory.generateClassOrObjectByActualClass(
|
private fun KtPsiFactory.generateClassOrObjectByActualClass(
|
||||||
project: Project,
|
project: Project,
|
||||||
actualClass: KtClassOrObject,
|
actualClass: KtClassOrObject,
|
||||||
isNested: Boolean
|
outerExpectedClasses: List<KtClassOrObject>
|
||||||
): KtClassOrObject {
|
): KtClassOrObject {
|
||||||
val expectedClass = createClassCopyByText(actualClass)
|
val expectedClass = createClassCopyByText(actualClass)
|
||||||
expectedClass.declarations.forEach {
|
expectedClass.declarations.forEach {
|
||||||
@@ -183,7 +200,7 @@ private fun KtPsiFactory.generateClassOrObjectByActualClass(
|
|||||||
expectedEntry.replace(createSuperTypeEntry(expectedEntry.typeReference!!.text))
|
expectedEntry.replace(createSuperTypeEntry(expectedEntry.typeReference!!.text))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!isNested) {
|
if (outerExpectedClasses.isEmpty()) {
|
||||||
expectedClass.addModifier(KtTokens.EXPECT_KEYWORD)
|
expectedClass.addModifier(KtTokens.EXPECT_KEYWORD)
|
||||||
} else {
|
} else {
|
||||||
expectedClass.makeNotActual()
|
expectedClass.makeNotActual()
|
||||||
@@ -195,15 +212,17 @@ private fun KtPsiFactory.generateClassOrObjectByActualClass(
|
|||||||
val expectedDeclaration: KtDeclaration = when (actualDeclaration) {
|
val expectedDeclaration: KtDeclaration = when (actualDeclaration) {
|
||||||
is KtClassOrObject ->
|
is KtClassOrObject ->
|
||||||
if (actualDeclaration !is KtEnumEntry) {
|
if (actualDeclaration !is KtEnumEntry) {
|
||||||
generateClassOrObjectByActualClass(project, actualDeclaration, isNested = true)
|
generateClassOrObjectByActualClass(project, actualDeclaration, outerExpectedClasses + expectedClass)
|
||||||
} else {
|
} else {
|
||||||
continue@declLoop
|
continue@declLoop
|
||||||
}
|
}
|
||||||
is KtCallableDeclaration -> {
|
is KtCallableDeclaration -> {
|
||||||
if (!actualDeclaration.hasActualModifier()) continue@declLoop
|
if (!actualDeclaration.hasActualModifier()) continue@declLoop
|
||||||
when (actualDeclaration) {
|
when (actualDeclaration) {
|
||||||
is KtFunction -> generateFunction(project, actualDeclaration, descriptor as FunctionDescriptor, expectedClass)
|
is KtFunction ->
|
||||||
is KtProperty -> generateProperty(project, actualDeclaration, descriptor as PropertyDescriptor, expectedClass)
|
generateFunction(project, actualDeclaration, descriptor as FunctionDescriptor, expectedClass, outerExpectedClasses)
|
||||||
|
is KtProperty ->
|
||||||
|
generateProperty(project, actualDeclaration, descriptor as PropertyDescriptor, expectedClass, outerExpectedClasses)
|
||||||
else -> continue@declLoop
|
else -> continue@declLoop
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -215,7 +234,8 @@ private fun KtPsiFactory.generateClassOrObjectByActualClass(
|
|||||||
for (actualProperty in actualClass.primaryConstructorParameters) {
|
for (actualProperty in actualClass.primaryConstructorParameters) {
|
||||||
if (!actualProperty.hasValOrVar() || !actualProperty.hasActualModifier()) continue
|
if (!actualProperty.hasValOrVar() || !actualProperty.hasActualModifier()) continue
|
||||||
val descriptor = actualProperty.toDescriptor() as? PropertyDescriptor ?: 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)
|
expectedClass.addDeclaration(expectedProperty)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -223,7 +243,8 @@ private fun KtPsiFactory.generateClassOrObjectByActualClass(
|
|||||||
if (expectedClass is KtClass && actualPrimaryConstructor != null) {
|
if (expectedClass is KtClass && actualPrimaryConstructor != null) {
|
||||||
val descriptor = actualPrimaryConstructor.toDescriptor()
|
val descriptor = actualPrimaryConstructor.toDescriptor()
|
||||||
if (descriptor is FunctionDescriptor) {
|
if (descriptor is FunctionDescriptor) {
|
||||||
val expectedPrimaryConstructor = generateFunction(project, actualPrimaryConstructor, descriptor, expectedClass)
|
val expectedPrimaryConstructor =
|
||||||
|
generateFunction(project, actualPrimaryConstructor, descriptor, expectedClass, outerExpectedClasses)
|
||||||
expectedClass.createPrimaryConstructorIfAbsent().replace(expectedPrimaryConstructor)
|
expectedClass.createPrimaryConstructorIfAbsent().replace(expectedPrimaryConstructor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -235,8 +256,15 @@ private fun generateFunction(
|
|||||||
project: Project,
|
project: Project,
|
||||||
actualFunction: KtFunction,
|
actualFunction: KtFunction,
|
||||||
descriptor: FunctionDescriptor,
|
descriptor: FunctionDescriptor,
|
||||||
targetClass: KtClassOrObject? = null
|
targetClass: KtClassOrObject?,
|
||||||
|
outerExpectedClasses: List<KtClassOrObject>
|
||||||
): KtFunction {
|
): KtFunction {
|
||||||
|
val accessibleClasses = outerExpectedClasses + listOfNotNull(targetClass)
|
||||||
|
descriptor.checkTypeParameterBoundsAccessibility(accessibleClasses)
|
||||||
|
descriptor.returnType?.checkAccessibility(accessibleClasses)
|
||||||
|
descriptor.valueParameters.forEach {
|
||||||
|
it.type.checkAccessibility(accessibleClasses)
|
||||||
|
}
|
||||||
val memberChooserObject = OverrideMemberChooserObject.create(
|
val memberChooserObject = OverrideMemberChooserObject.create(
|
||||||
actualFunction, descriptor, descriptor,
|
actualFunction, descriptor, descriptor,
|
||||||
OverrideMemberChooserObject.BodyType.NO_BODY
|
OverrideMemberChooserObject.BodyType.NO_BODY
|
||||||
@@ -252,8 +280,12 @@ private fun generateProperty(
|
|||||||
project: Project,
|
project: Project,
|
||||||
actualProperty: KtNamedDeclaration,
|
actualProperty: KtNamedDeclaration,
|
||||||
descriptor: PropertyDescriptor,
|
descriptor: PropertyDescriptor,
|
||||||
targetClass: KtClassOrObject? = null
|
targetClass: KtClassOrObject?,
|
||||||
|
outerExpectedClasses: List<KtClassOrObject>
|
||||||
): KtProperty {
|
): KtProperty {
|
||||||
|
val accessibleClasses = outerExpectedClasses + listOfNotNull(targetClass)
|
||||||
|
descriptor.checkTypeParameterBoundsAccessibility(accessibleClasses)
|
||||||
|
descriptor.type.checkAccessibility(accessibleClasses)
|
||||||
val memberChooserObject = OverrideMemberChooserObject.create(
|
val memberChooserObject = OverrideMemberChooserObject.create(
|
||||||
actualProperty, descriptor, descriptor,
|
actualProperty, descriptor, descriptor,
|
||||||
OverrideMemberChooserObject.BodyType.NO_BODY
|
OverrideMemberChooserObject.BodyType.NO_BODY
|
||||||
@@ -265,6 +297,47 @@ private fun generateProperty(
|
|||||||
} as KtProperty
|
} as KtProperty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun CallableMemberDescriptor.checkTypeParameterBoundsAccessibility(accessibleClasses: List<KtClassOrObject>) {
|
||||||
|
typeParameters.forEach { typeParameter ->
|
||||||
|
typeParameter.upperBounds.forEach { upperBound ->
|
||||||
|
upperBound.checkAccessibility(accessibleClasses)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun KotlinType.checkAccessibility(accessibleClasses: List<KtClassOrObject>) {
|
||||||
|
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"
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
expect class Some {
|
||||||
|
companion object {
|
||||||
|
fun createMe(): Some
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
// "Create expected class in common module testModule_Common" "true"
|
||||||
|
// DISABLE-ERRORS
|
||||||
|
|
||||||
|
actual class <caret>Some {
|
||||||
|
actual companion object {
|
||||||
|
actual fun createMe() = Some()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
// "Create expected class in common module testModule_Common" "true"
|
||||||
|
// DISABLE-ERRORS
|
||||||
|
|
||||||
|
actual class <caret>Some {
|
||||||
|
actual companion object {
|
||||||
|
actual fun createMe() = Some()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
expect class SomeString
|
||||||
|
// It would be great to have SomeString in foo() below, but it's problematic
|
||||||
+3
@@ -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
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
// "Create expected function in common module testModule_Common" "true"
|
||||||
|
// DISABLE-ERRORS
|
||||||
|
|
||||||
|
actual typealias SomeString = String
|
||||||
|
|
||||||
|
actual fun <caret>foo(): SomeString = ""
|
||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
// "Create expected function in common module testModule_Common" "true"
|
||||||
|
// DISABLE-ERRORS
|
||||||
|
|
||||||
|
actual typealias SomeString = String
|
||||||
|
|
||||||
|
actual fun foo(): SomeString = ""
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
expect fun foo(): String
|
||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
// "Create expected function in common module testModule_Common" "true"
|
||||||
|
// DISABLE-ERRORS
|
||||||
|
|
||||||
|
typealias SomeString = String
|
||||||
|
|
||||||
|
actual fun <caret>foo(): SomeString = ""
|
||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
// "Create expected function in common module testModule_Common" "true"
|
||||||
|
// DISABLE-ERRORS
|
||||||
|
|
||||||
|
typealias SomeString = String
|
||||||
|
|
||||||
|
actual fun foo(): SomeString = ""
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
expect class Some
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
expect class Some
|
||||||
|
|
||||||
|
expect fun foo(some: List<Some>)
|
||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
// "Create expected function in common module testModule_Common" "true"
|
||||||
|
// DISABLE-ERRORS
|
||||||
|
|
||||||
|
actual class Some
|
||||||
|
|
||||||
|
actual fun <caret>foo(some: List<Some>) {}
|
||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
// "Create expected function in common module testModule_Common" "true"
|
||||||
|
// DISABLE-ERRORS
|
||||||
|
|
||||||
|
actual class Some
|
||||||
|
|
||||||
|
actual fun foo(some: List<Some>) {}
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
// To be implemented
|
||||||
+7
@@ -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 <T : Some> <caret>foo(some: List<T>) {}
|
||||||
+7
@@ -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 <T : Some> foo(some: List<T>) {}
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
// To be implemented
|
||||||
+7
@@ -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 <caret>foo(some: Some) {}
|
||||||
+7
@@ -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) {}
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
// To be implemented
|
||||||
+7
@@ -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 <caret>foo(some: List<Some>) {}
|
||||||
Vendored
+7
@@ -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<Some>) {}
|
||||||
+1
@@ -1,4 +1,5 @@
|
|||||||
// "Create expected function in common module proj_Common" "true"
|
// "Create expected function in common module proj_Common" "true"
|
||||||
|
// SHOULD_FAIL_WITH: Cannot generate expected function: Type java.util.ArrayList<kotlin.Any> is not accessible from common code
|
||||||
// DISABLE-ERRORS
|
// DISABLE-ERRORS
|
||||||
|
|
||||||
import java.util.ArrayList
|
import java.util.ArrayList
|
||||||
|
|||||||
+1
@@ -1,4 +1,5 @@
|
|||||||
// "Create expected function in common module proj_Common" "true"
|
// "Create expected function in common module proj_Common" "true"
|
||||||
|
// SHOULD_FAIL_WITH: Cannot generate expected function: Type java.util.ArrayList<kotlin.Any> is not accessible from common code
|
||||||
// DISABLE-ERRORS
|
// DISABLE-ERRORS
|
||||||
|
|
||||||
import java.util.ArrayList
|
import java.util.ArrayList
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import com.intellij.codeInsight.daemon.quickFix.ActionHint
|
|||||||
import com.intellij.codeInsight.daemon.quickFix.LightQuickFixTestCase
|
import com.intellij.codeInsight.daemon.quickFix.LightQuickFixTestCase
|
||||||
import com.intellij.codeInsight.intention.IntentionAction
|
import com.intellij.codeInsight.intention.IntentionAction
|
||||||
import com.intellij.openapi.command.CommandProcessor
|
import com.intellij.openapi.command.CommandProcessor
|
||||||
|
import com.intellij.testFramework.UsefulTestCase
|
||||||
import junit.framework.ComparisonFailure
|
import junit.framework.ComparisonFailure
|
||||||
import junit.framework.TestCase
|
import junit.framework.TestCase
|
||||||
import org.jetbrains.kotlin.idea.inspections.findExistingEditor
|
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.psi.KtFile
|
||||||
import org.jetbrains.kotlin.test.InTextDirectivesUtils
|
import org.jetbrains.kotlin.test.InTextDirectivesUtils
|
||||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||||
|
import org.junit.Assert
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
abstract class AbstractQuickFixMultiModuleTest : AbstractMultiModuleTest(), QuickFixTest {
|
abstract class AbstractQuickFixMultiModuleTest : AbstractMultiModuleTest(), QuickFixTest {
|
||||||
@@ -42,6 +44,7 @@ abstract class AbstractQuickFixMultiModuleTest : AbstractMultiModuleTest(), Quic
|
|||||||
enableInspectionTools(*inspections)
|
enableInspectionTools(*inspections)
|
||||||
|
|
||||||
CommandProcessor.getInstance().executeCommand(project, {
|
CommandProcessor.getInstance().executeCommand(project, {
|
||||||
|
var expectedErrorMessage: String = ""
|
||||||
try {
|
try {
|
||||||
val actionHint = ActionHint.parse(actionFile, actionFileText)
|
val actionHint = ActionHint.parse(actionFile, actionFileText)
|
||||||
val text = actionHint.expectedText
|
val text = actionHint.expectedText
|
||||||
@@ -52,24 +55,28 @@ abstract class AbstractQuickFixMultiModuleTest : AbstractMultiModuleTest(), Quic
|
|||||||
DirectiveBasedActionUtils.checkForUnexpectedErrors(actionFile)
|
DirectiveBasedActionUtils.checkForUnexpectedErrors(actionFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
expectedErrorMessage = InTextDirectivesUtils.findStringWithPrefixes(actionFileText, "// SHOULD_FAIL_WITH: ") ?: ""
|
||||||
|
|
||||||
AbstractQuickFixMultiFileTest.doAction(
|
AbstractQuickFixMultiFileTest.doAction(
|
||||||
text, file, editor, actionShouldBeAvailable, actionFileName, this::availableActions, this::doHighlighting,
|
text, file, editor, actionShouldBeAvailable, actionFileName, this::availableActions, this::doHighlighting,
|
||||||
InTextDirectivesUtils.isDirectiveDefined(actionFile.text, "// SHOULD_BE_AVAILABLE_AFTER_EXECUTION")
|
InTextDirectivesUtils.isDirectiveDefined(actionFile.text, "// SHOULD_BE_AVAILABLE_AFTER_EXECUTION")
|
||||||
)
|
)
|
||||||
|
|
||||||
if (actionShouldBeAvailable) {
|
if (actionShouldBeAvailable) {
|
||||||
compareToExpected()
|
compareToExpected()
|
||||||
}
|
}
|
||||||
}
|
UsefulTestCase.assertEmpty(expectedErrorMessage)
|
||||||
catch (e: ComparisonFailure) {
|
} catch (e: ComparisonFailure) {
|
||||||
throw e
|
throw e
|
||||||
}
|
} catch (e: AssertionError) {
|
||||||
catch (e: AssertionError) {
|
|
||||||
throw e
|
throw e
|
||||||
}
|
} catch (e: Throwable) {
|
||||||
catch (e: Throwable) {
|
if (expectedErrorMessage.isEmpty()) {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
TestCase.fail(getTestName(true))
|
TestCase.fail(getTestName(true))
|
||||||
|
} else {
|
||||||
|
Assert.assertEquals("Wrong exception message", expectedErrorMessage, e.message)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, "", "")
|
}, "", "")
|
||||||
}
|
}
|
||||||
|
|||||||
+35
@@ -294,6 +294,11 @@ public class QuickFixMultiModuleTestGenerated extends AbstractQuickFixMultiModul
|
|||||||
runTest("idea/testData/multiModuleQuickFix/expectClassWithSupertype/");
|
runTest("idea/testData/multiModuleQuickFix/expectClassWithSupertype/");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("expectCompanion")
|
||||||
|
public void testExpectCompanion() throws Exception {
|
||||||
|
runTest("idea/testData/multiModuleQuickFix/expectCompanion/");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("expectDataClass")
|
@TestMetadata("expectDataClass")
|
||||||
public void testExpectDataClass() throws Exception {
|
public void testExpectDataClass() throws Exception {
|
||||||
runTest("idea/testData/multiModuleQuickFix/expectDataClass/");
|
runTest("idea/testData/multiModuleQuickFix/expectDataClass/");
|
||||||
@@ -309,6 +314,36 @@ public class QuickFixMultiModuleTestGenerated extends AbstractQuickFixMultiModul
|
|||||||
runTest("idea/testData/multiModuleQuickFix/expectEnumEmpty/");
|
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")
|
@TestMetadata("expectFunWithJdk")
|
||||||
public void testExpectFunWithJdk() throws Exception {
|
public void testExpectFunWithJdk() throws Exception {
|
||||||
runTest("idea/testData/multiModuleQuickFix/expectFunWithJdk/");
|
runTest("idea/testData/multiModuleQuickFix/expectFunWithJdk/");
|
||||||
|
|||||||
Reference in New Issue
Block a user