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 595f318cff7..a45414b4faf 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/expectactual/CreateExpectedFix.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/expectactual/CreateExpectedFix.kt @@ -133,7 +133,7 @@ class CreateExpectedClassFix( chooseMembers(project, members, prefix) ?: return@block null } }.let { selectedElements -> - val selectedClasses = findClasses(selectedElements) + val selectedClasses = findClasses(selectedElements + klass) if (selectedClasses != existingClasses) { val (resultDeclarations, withErrors) = selectedElements.partition { it.checkTypeAccessibilityInModule(commonModule, selectedClasses) 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 994846b068b..6bb41268cd8 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/expectactual/ExpectActualUtils.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/expectactual/ExpectActualUtils.kt @@ -9,6 +9,7 @@ import com.intellij.openapi.module.Module import com.intellij.openapi.project.Project import com.intellij.psi.JavaDirectoryService import com.intellij.psi.search.GlobalSearchScope +import org.jetbrains.kotlin.backend.common.descriptors.allParameters import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.idea.caches.project.implementedDescriptors import org.jetbrains.kotlin.idea.caches.project.isTestModule @@ -45,6 +46,7 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.types.AbbreviatedType import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlin.types.TypeProjection import org.jetbrains.kotlin.utils.addToStdlib.safeAs fun createFileForDeclaration(module: Module, declaration: KtNamedDeclaration): KtFile? { @@ -318,20 +320,34 @@ class KotlinTypeInaccessibleException(val type: KotlinType) : Exception() { get() = "Type ${type.getJetTypeFqName(true)} is not accessible from common code" } -fun KtNamedDeclaration.checkTypeAccessibilityInModule(module: Module, existedClasses: Set = emptySet()): Boolean { - if (hasPrivateModifier()) return false - val types = when (this) { - is KtClassOrObject -> return fqName?.canFindClassInModule(project, module, existedClasses) == true - is KtCallableDeclaration -> { - val descriptor = descriptor?.safeAs() ?: return false - val returnType = descriptor.returnType ?: return false - (listOfNotNull(descriptor.extensionReceiverParameter) + descriptor.valueParameters).map { it.type } + returnType - } - else -> return false - } +fun DeclarationDescriptor.checkTypeAccessibilityInModule( + project: Project, + module: Module, + existedClasses: Set = emptySet() +): Boolean = collectAllTypes().all { it?.canFindClassInModule(project, module, existedClasses) == true } - val project = project - return types.all { it.fqName?.canFindClassInModule(project, module, existedClasses) ?: false } +private fun DeclarationDescriptor.collectAllTypes(): Sequence { + return when (this) { + is ClassDescriptor -> declaredTypeParameters.asSequence().flatMap(DeclarationDescriptor::collectAllTypes) + is CallableDescriptor -> { + val returnType = returnType ?: return sequenceOf(null) + returnType.collectAllTypes() + allParameters.asSequence().map { it.type }.flatMap(KotlinType::collectAllTypes) + } + is TypeParameterDescriptor -> { + val upperBounds = upperBounds + if (upperBounds.isEmpty()) sequenceOf(fqNameOrNull()) + else upperBounds.asSequence().flatMap(KotlinType::collectAllTypes) + } + else -> emptySequence() + } +} + +private fun KotlinType.collectAllTypes(): Sequence = sequenceOf(fqName) + arguments.asSequence() + .map(TypeProjection::getType) + .flatMap(KotlinType::collectAllTypes) + +fun KtNamedDeclaration.checkTypeAccessibilityInModule(module: Module, existedClasses: Set = emptySet()): Boolean { + return !hasPrivateModifier() && descriptor?.checkTypeAccessibilityInModule(project, module, existedClasses) == true } val KotlinType.fqName: FqName? get() = constructor.declarationDescriptor?.fqNameOrNull()