ExpectActualUtils: add type arguments accessibility check

This commit is contained in:
Dmitry Gridin
2019-08-06 17:27:05 +03:00
parent 5884c65857
commit bad9459978
2 changed files with 30 additions and 14 deletions
@@ -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)
@@ -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<String> = 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<CallableDescriptor>() ?: 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<String> = 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<FqName?> {
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<FqName?> = sequenceOf(fqName) + arguments.asSequence()
.map(TypeProjection::getType)
.flatMap(KotlinType::collectAllTypes)
fun KtNamedDeclaration.checkTypeAccessibilityInModule(module: Module, existedClasses: Set<String> = emptySet()): Boolean {
return !hasPrivateModifier() && descriptor?.checkTypeAccessibilityInModule(project, module, existedClasses) == true
}
val KotlinType.fqName: FqName? get() = constructor.declarationDescriptor?.fqNameOrNull()