ExpectActualUtils: merge generateFunction with generateProperty to generateCallable & remove old checker
This commit is contained in:
@@ -21,8 +21,7 @@ import com.intellij.openapi.editor.Editor
|
|||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import com.intellij.psi.codeStyle.CodeStyleManager
|
import com.intellij.psi.codeStyle.CodeStyleManager
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
|
||||||
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
|
||||||
@@ -60,12 +59,9 @@ class AddActualFix(
|
|||||||
val checker = TypeAccessibilityChecker.create(project, module)
|
val checker = TypeAccessibilityChecker.create(project, module)
|
||||||
for (missedDeclaration in missedDeclarationPointers.mapNotNull { it.element }) {
|
for (missedDeclaration in missedDeclarationPointers.mapNotNull { it.element }) {
|
||||||
val actualDeclaration = when (missedDeclaration) {
|
val actualDeclaration = when (missedDeclaration) {
|
||||||
is KtClassOrObject -> factory.generateClassOrObject(project, false, missedDeclaration, checker, listOf(element))
|
is KtClassOrObject -> factory.generateClassOrObject(project, false, missedDeclaration, checker)
|
||||||
is KtFunction -> missedDeclaration.toDescriptor()?.safeAs<FunctionDescriptor>()?.let {
|
is KtFunction, is KtProperty -> missedDeclaration.toDescriptor()?.safeAs<CallableMemberDescriptor>()?.let {
|
||||||
generateFunction(project, false, missedDeclaration, it, element, checker = checker)
|
generateCallable(project, false, missedDeclaration, it, element, checker = checker)
|
||||||
}
|
|
||||||
is KtProperty -> missedDeclaration.toDescriptor()?.safeAs<PropertyDescriptor>()?.let {
|
|
||||||
generateProperty(project, false, missedDeclaration, it, element, checker = checker)
|
|
||||||
}
|
}
|
||||||
else -> null
|
else -> null
|
||||||
} ?: continue
|
} ?: continue
|
||||||
|
|||||||
@@ -21,8 +21,7 @@ import com.intellij.openapi.editor.Editor
|
|||||||
import com.intellij.openapi.module.Module
|
import com.intellij.openapi.module.Module
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import org.jetbrains.kotlin.analyzer.ModuleInfo
|
import org.jetbrains.kotlin.analyzer.ModuleInfo
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
|
||||||
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
|
||||||
@@ -74,8 +73,11 @@ sealed class CreateActualFix<D : KtNamedDeclaration>(
|
|||||||
val actualPlatform = actualModuleDescriptor.platform ?: return null
|
val actualPlatform = actualModuleDescriptor.platform ?: return null
|
||||||
return when (declaration) {
|
return when (declaration) {
|
||||||
is KtClassOrObject -> CreateActualClassFix(declaration, actualModule, actualPlatform)
|
is KtClassOrObject -> CreateActualClassFix(declaration, actualModule, actualPlatform)
|
||||||
is KtFunction -> CreateActualFunctionFix(declaration, actualModule, actualPlatform)
|
is KtFunction, is KtProperty -> CreateActualCallableMemberFix(
|
||||||
is KtProperty -> CreateActualPropertyFix(declaration, actualModule, actualPlatform)
|
declaration as KtCallableDeclaration,
|
||||||
|
actualModule,
|
||||||
|
actualPlatform
|
||||||
|
)
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -90,21 +92,12 @@ class CreateActualClassFix(
|
|||||||
generateClassOrObject(project, false, element, checker = checker)
|
generateClassOrObject(project, false, element, checker = checker)
|
||||||
})
|
})
|
||||||
|
|
||||||
class CreateActualPropertyFix(
|
class CreateActualCallableMemberFix(
|
||||||
property: KtProperty,
|
declaration: KtCallableDeclaration,
|
||||||
actualModule: Module,
|
actualModule: Module,
|
||||||
actualPlatform: TargetPlatform
|
actualPlatform: TargetPlatform
|
||||||
) : CreateActualFix<KtProperty>(property, actualModule, actualPlatform, { project, checker, element ->
|
) : CreateActualFix<KtCallableDeclaration>(declaration, actualModule, actualPlatform, { project, checker, element ->
|
||||||
val descriptor = element.toDescriptor() as? PropertyDescriptor
|
val descriptor = element.toDescriptor() as? CallableMemberDescriptor
|
||||||
descriptor?.let { generateProperty(project, false, element, descriptor, checker = checker) }
|
descriptor?.let { generateCallable(project, false, element, descriptor, checker = checker) }
|
||||||
})
|
|
||||||
|
|
||||||
class CreateActualFunctionFix(
|
|
||||||
function: KtFunction,
|
|
||||||
actualModule: Module,
|
|
||||||
actualPlatform: TargetPlatform
|
|
||||||
) : CreateActualFix<KtFunction>(function, actualModule, actualPlatform, { project, checker, element ->
|
|
||||||
val descriptor = element.toDescriptor() as? FunctionDescriptor
|
|
||||||
descriptor?.let { generateFunction(project, false, element, descriptor, checker = checker) }
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -13,10 +13,9 @@ import com.intellij.openapi.module.Module
|
|||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.openapi.ui.showOkNoDialog
|
import com.intellij.openapi.ui.showOkNoDialog
|
||||||
import com.intellij.openapi.util.text.StringUtil
|
import com.intellij.openapi.util.text.StringUtil
|
||||||
|
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
|
||||||
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
|
||||||
@@ -90,10 +89,9 @@ sealed class CreateExpectedFix<D : KtNamedDeclaration>(
|
|||||||
?: return emptyList()
|
?: return emptyList()
|
||||||
return when (actualDeclaration) {
|
return when (actualDeclaration) {
|
||||||
is KtClassOrObject -> expectedModules.map { CreateExpectedClassFix(actualDeclaration, expectedContainingClass, it) }
|
is KtClassOrObject -> expectedModules.map { CreateExpectedClassFix(actualDeclaration, expectedContainingClass, it) }
|
||||||
is KtFunction -> expectedModules.map { CreateExpectedFunctionFix(actualDeclaration, expectedContainingClass, it) }
|
is KtProperty, is KtParameter, is KtFunction -> expectedModules.map {
|
||||||
is KtProperty, is KtParameter -> expectedModules.map {
|
CreateExpectedCallableMemberFix(
|
||||||
CreateExpectedPropertyFix(
|
actualDeclaration as KtCallableDeclaration,
|
||||||
actualDeclaration,
|
|
||||||
expectedContainingClass,
|
expectedContainingClass,
|
||||||
it
|
it
|
||||||
)
|
)
|
||||||
@@ -163,7 +161,7 @@ class CreateExpectedClassFix(
|
|||||||
repairActualModifiers(originalElements + klass, resultDeclarations.toSet())
|
repairActualModifiers(originalElements + klass, resultDeclarations.toSet())
|
||||||
}
|
}
|
||||||
|
|
||||||
generateClassOrObject(project, true, element, checker, listOfNotNull(outerExpectedClass))
|
generateClassOrObject(project, true, element, checker)
|
||||||
})
|
})
|
||||||
|
|
||||||
private tailrec fun TypeAccessibilityChecker.findAndApplyExistingClasses(elements: Collection<KtNamedDeclaration>): HashSet<String> {
|
private tailrec fun TypeAccessibilityChecker.findAndApplyExistingClasses(elements: Collection<KtNamedDeclaration>): HashSet<String> {
|
||||||
@@ -294,42 +292,19 @@ private fun KtNamedDeclaration.selected(): Sequence<KtNamedDeclaration> {
|
|||||||
return sequenceOf(this) + additionalSequence + containingClassOrObject?.selected().orEmpty()
|
return sequenceOf(this) + additionalSequence + containingClassOrObject?.selected().orEmpty()
|
||||||
}
|
}
|
||||||
|
|
||||||
class CreateExpectedPropertyFix(
|
class CreateExpectedCallableMemberFix(
|
||||||
property: KtNamedDeclaration,
|
declaration: KtCallableDeclaration,
|
||||||
targetExpectedClass: KtClassOrObject?,
|
targetExpectedClass: KtClassOrObject?,
|
||||||
commonModule: Module
|
commonModule: Module
|
||||||
) : CreateExpectedFix<KtNamedDeclaration>(property, targetExpectedClass, commonModule, block@{ project, checker, element ->
|
) : CreateExpectedFix<KtNamedDeclaration>(declaration, targetExpectedClass, commonModule, block@{ project, checker, element ->
|
||||||
if (!checker.checkAccessibility(element)) {
|
if (!checker.checkAccessibility(element)) {
|
||||||
showUnknownTypesError(element)
|
showUnknownTypesError(element)
|
||||||
return@block null
|
return@block null
|
||||||
}
|
}
|
||||||
val descriptor = element.toDescriptor() as? PropertyDescriptor
|
val descriptor = element.toDescriptor() as? CallableMemberDescriptor
|
||||||
checker.existingFqNames = targetExpectedClass?.getSuperNames()?.toSet().orEmpty()
|
checker.existingFqNames = targetExpectedClass?.getSuperNames()?.toSet().orEmpty()
|
||||||
descriptor?.let {
|
descriptor?.let {
|
||||||
generateProperty(
|
generateCallable(
|
||||||
project,
|
|
||||||
true,
|
|
||||||
element,
|
|
||||||
descriptor,
|
|
||||||
targetExpectedClass,
|
|
||||||
checker = checker
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
class CreateExpectedFunctionFix(
|
|
||||||
function: KtFunction,
|
|
||||||
targetExpectedClass: KtClassOrObject?,
|
|
||||||
commonModule: Module
|
|
||||||
) : CreateExpectedFix<KtFunction>(function, targetExpectedClass, commonModule, block@{ project, checker, element ->
|
|
||||||
if (!checker.checkAccessibility(element)) {
|
|
||||||
showUnknownTypesError(element)
|
|
||||||
return@block null
|
|
||||||
}
|
|
||||||
val descriptor = element.toDescriptor() as? FunctionDescriptor
|
|
||||||
checker.existingFqNames = targetExpectedClass?.getSuperNames()?.toSet().orEmpty()
|
|
||||||
descriptor?.let {
|
|
||||||
generateFunction(
|
|
||||||
project,
|
project,
|
||||||
true,
|
true,
|
||||||
element,
|
element,
|
||||||
|
|||||||
@@ -7,10 +7,10 @@ package org.jetbrains.kotlin.idea.quickfix.expectactual
|
|||||||
|
|
||||||
import com.intellij.openapi.module.Module
|
import com.intellij.openapi.module.Module
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.openapi.util.text.StringUtil
|
||||||
import com.intellij.psi.JavaDirectoryService
|
import com.intellij.psi.JavaDirectoryService
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
||||||
import org.jetbrains.kotlin.idea.caches.project.implementedDescriptors
|
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyzeWithContent
|
import org.jetbrains.kotlin.idea.caches.resolve.analyzeWithContent
|
||||||
import org.jetbrains.kotlin.idea.codeInsight.shorten.addToBeShortenedDescendantsToWaitingSet
|
import org.jetbrains.kotlin.idea.codeInsight.shorten.addToBeShortenedDescendantsToWaitingSet
|
||||||
import org.jetbrains.kotlin.idea.core.KotlinNameSuggester
|
import org.jetbrains.kotlin.idea.core.KotlinNameSuggester
|
||||||
@@ -23,25 +23,21 @@ import org.jetbrains.kotlin.idea.core.overrideImplement.OverrideMemberChooserObj
|
|||||||
import org.jetbrains.kotlin.idea.core.overrideImplement.generateMember
|
import org.jetbrains.kotlin.idea.core.overrideImplement.generateMember
|
||||||
import org.jetbrains.kotlin.idea.core.overrideImplement.makeNotActual
|
import org.jetbrains.kotlin.idea.core.overrideImplement.makeNotActual
|
||||||
import org.jetbrains.kotlin.idea.core.toDescriptor
|
import org.jetbrains.kotlin.idea.core.toDescriptor
|
||||||
import org.jetbrains.kotlin.idea.project.platform
|
|
||||||
import org.jetbrains.kotlin.idea.refactoring.createKotlinFile
|
import org.jetbrains.kotlin.idea.refactoring.createKotlinFile
|
||||||
import org.jetbrains.kotlin.idea.util.*
|
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
||||||
import org.jetbrains.kotlin.idea.util.application.runWriteAction
|
import org.jetbrains.kotlin.idea.util.application.runWriteAction
|
||||||
import org.jetbrains.kotlin.js.descriptorUtils.getJetTypeFqName
|
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.lexer.KtTokens
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.platform.isCommon
|
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
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.DescriptorToSourceUtils
|
|
||||||
import org.jetbrains.kotlin.resolve.checkers.ExpectedActualDeclarationChecker
|
import org.jetbrains.kotlin.resolve.checkers.ExpectedActualDeclarationChecker
|
||||||
import org.jetbrains.kotlin.resolve.checkers.ExperimentalUsageChecker
|
import org.jetbrains.kotlin.resolve.checkers.ExperimentalUsageChecker
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameOrNull
|
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameOrNull
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
|
||||||
import org.jetbrains.kotlin.resolve.source.KotlinSourceElement
|
import org.jetbrains.kotlin.resolve.source.KotlinSourceElement
|
||||||
import org.jetbrains.kotlin.types.AbbreviatedType
|
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||||
|
|
||||||
@@ -111,8 +107,7 @@ internal fun KtPsiFactory.generateClassOrObject(
|
|||||||
project: Project,
|
project: Project,
|
||||||
generateExpectClass: Boolean,
|
generateExpectClass: Boolean,
|
||||||
originalClass: KtClassOrObject,
|
originalClass: KtClassOrObject,
|
||||||
checker: TypeAccessibilityChecker,
|
checker: TypeAccessibilityChecker
|
||||||
outerClasses: List<KtClassOrObject> = emptyList()
|
|
||||||
): KtClassOrObject {
|
): KtClassOrObject {
|
||||||
val generatedClass = createClassHeaderCopyByText(originalClass)
|
val generatedClass = createClassHeaderCopyByText(originalClass)
|
||||||
val context = originalClass.analyzeWithContent()
|
val context = originalClass.analyzeWithContent()
|
||||||
@@ -132,7 +127,7 @@ internal fun KtPsiFactory.generateClassOrObject(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (generateExpectClass) {
|
if (generateExpectClass) {
|
||||||
if (outerClasses.isEmpty()) {
|
if (originalClass.isTopLevel()) {
|
||||||
generatedClass.addModifier(KtTokens.EXPECT_KEYWORD)
|
generatedClass.addModifier(KtTokens.EXPECT_KEYWORD)
|
||||||
} else {
|
} else {
|
||||||
generatedClass.makeNotActual()
|
generatedClass.makeNotActual()
|
||||||
@@ -144,10 +139,6 @@ internal fun KtPsiFactory.generateClassOrObject(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val existingClasses = originalClass.declarations.asSequence().filterIsInstance<KtClassOrObject>().filter {
|
|
||||||
it.isEffectivelyActual(false)
|
|
||||||
}.toList() + generatedClass + outerClasses
|
|
||||||
|
|
||||||
val existingFqNamesWithSuperTypes = (checker.existingFqNames + superNames).toSet()
|
val existingFqNamesWithSuperTypes = (checker.existingFqNames + superNames).toSet()
|
||||||
declLoop@ for (originalDeclaration in originalClass.declarations) {
|
declLoop@ for (originalDeclaration in originalClass.declarations) {
|
||||||
val descriptor = originalDeclaration.toDescriptor() ?: continue
|
val descriptor = originalDeclaration.toDescriptor() ?: continue
|
||||||
@@ -157,17 +148,15 @@ internal fun KtPsiFactory.generateClassOrObject(
|
|||||||
project,
|
project,
|
||||||
generateExpectClass,
|
generateExpectClass,
|
||||||
originalDeclaration,
|
originalDeclaration,
|
||||||
checker,
|
checker
|
||||||
existingClasses
|
|
||||||
)
|
)
|
||||||
is KtFunction, is KtProperty -> checker.runInContext(existingFqNamesWithSuperTypes) {
|
is KtFunction, is KtProperty -> checker.runInContext(existingFqNamesWithSuperTypes) {
|
||||||
generateCallable(
|
generateCallable(
|
||||||
project,
|
project,
|
||||||
generateExpectClass,
|
generateExpectClass,
|
||||||
originalDeclaration as KtCallableDeclaration,
|
originalDeclaration as KtCallableDeclaration,
|
||||||
descriptor as CallableDescriptor,
|
descriptor as CallableMemberDescriptor,
|
||||||
generatedClass,
|
generatedClass,
|
||||||
existingClasses,
|
|
||||||
this
|
this
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -180,13 +169,12 @@ internal fun KtPsiFactory.generateClassOrObject(
|
|||||||
if (!originalProperty.hasValOrVar() || !originalProperty.hasActualModifier()) continue
|
if (!originalProperty.hasValOrVar() || !originalProperty.hasActualModifier()) continue
|
||||||
val descriptor = originalProperty.toDescriptor() as? PropertyDescriptor ?: continue
|
val descriptor = originalProperty.toDescriptor() as? PropertyDescriptor ?: continue
|
||||||
checker.runInContext(existingFqNamesWithSuperTypes) {
|
checker.runInContext(existingFqNamesWithSuperTypes) {
|
||||||
val generatedProperty = generateProperty(
|
val generatedProperty = generateCallable(
|
||||||
project,
|
project,
|
||||||
generateExpectClass,
|
generateExpectClass,
|
||||||
originalProperty,
|
originalProperty,
|
||||||
descriptor,
|
descriptor,
|
||||||
generatedClass,
|
generatedClass,
|
||||||
outerClasses,
|
|
||||||
this
|
this
|
||||||
)
|
)
|
||||||
generatedClass.addDeclaration(generatedProperty)
|
generatedClass.addDeclaration(generatedProperty)
|
||||||
@@ -202,13 +190,12 @@ internal fun KtPsiFactory.generateClassOrObject(
|
|||||||
val descriptor = originalPrimaryConstructor.toDescriptor()
|
val descriptor = originalPrimaryConstructor.toDescriptor()
|
||||||
if (descriptor is FunctionDescriptor) {
|
if (descriptor is FunctionDescriptor) {
|
||||||
checker.runInContext(existingFqNamesWithSuperTypes) {
|
checker.runInContext(existingFqNamesWithSuperTypes) {
|
||||||
val expectedPrimaryConstructor = generateFunction(
|
val expectedPrimaryConstructor = generateCallable(
|
||||||
project,
|
project,
|
||||||
generateExpectClass,
|
generateExpectClass,
|
||||||
originalPrimaryConstructor,
|
originalPrimaryConstructor,
|
||||||
descriptor,
|
descriptor,
|
||||||
generatedClass,
|
generatedClass,
|
||||||
outerClasses,
|
|
||||||
this
|
this
|
||||||
)
|
)
|
||||||
generatedClass.createPrimaryConstructorIfAbsent().replace(expectedPrimaryConstructor)
|
generatedClass.createPrimaryConstructorIfAbsent().replace(expectedPrimaryConstructor)
|
||||||
@@ -266,52 +253,14 @@ private val forbiddenAnnotationFqNames = setOf(
|
|||||||
internal fun generateCallable(
|
internal fun generateCallable(
|
||||||
project: Project,
|
project: Project,
|
||||||
generateExpect: Boolean,
|
generateExpect: Boolean,
|
||||||
originalDeclaration: KtCallableDeclaration,
|
originalDeclaration: KtDeclaration,
|
||||||
descriptor: CallableDescriptor,
|
descriptor: CallableMemberDescriptor,
|
||||||
generatedClass: KtClassOrObject? = null,
|
generatedClass: KtClassOrObject? = null,
|
||||||
outerClasses: List<KtClassOrObject> = emptyList(),
|
|
||||||
checker: TypeAccessibilityChecker
|
checker: TypeAccessibilityChecker
|
||||||
) = when (originalDeclaration) {
|
): KtCallableDeclaration {
|
||||||
is KtFunction -> generateFunction(
|
if (generateExpect) descriptor.checkAccessibility(checker)
|
||||||
project,
|
|
||||||
generateExpect,
|
|
||||||
originalDeclaration,
|
|
||||||
descriptor as FunctionDescriptor,
|
|
||||||
generatedClass,
|
|
||||||
outerClasses,
|
|
||||||
checker
|
|
||||||
)
|
|
||||||
is KtProperty -> generateProperty(
|
|
||||||
project,
|
|
||||||
generateExpect,
|
|
||||||
originalDeclaration,
|
|
||||||
descriptor as PropertyDescriptor,
|
|
||||||
generatedClass,
|
|
||||||
outerClasses,
|
|
||||||
checker
|
|
||||||
)
|
|
||||||
else -> error("Unsupported operation for $originalDeclaration")
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun generateFunction(
|
|
||||||
project: Project,
|
|
||||||
generateExpect: Boolean,
|
|
||||||
originalFunction: KtFunction,
|
|
||||||
descriptor: FunctionDescriptor,
|
|
||||||
generatedClass: KtClassOrObject? = null,
|
|
||||||
outerClasses: List<KtClassOrObject> = emptyList(),
|
|
||||||
checker: TypeAccessibilityChecker
|
|
||||||
): KtFunction {
|
|
||||||
if (generateExpect) {
|
|
||||||
val accessibleClasses = outerClasses + listOfNotNull(generatedClass)
|
|
||||||
descriptor.checkTypeParameterBoundsAccessibility(accessibleClasses)
|
|
||||||
descriptor.returnType?.checkAccessibility(accessibleClasses)
|
|
||||||
descriptor.valueParameters.forEach {
|
|
||||||
it.type.checkAccessibility(accessibleClasses)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val memberChooserObject = create(
|
val memberChooserObject = create(
|
||||||
originalFunction, descriptor, descriptor,
|
originalDeclaration, descriptor, descriptor,
|
||||||
if (generateExpect || descriptor.modality == Modality.ABSTRACT) NO_BODY else EMPTY_OR_TEMPLATE
|
if (generateExpect || descriptor.modality == Modality.ABSTRACT) NO_BODY else EMPTY_OR_TEMPLATE
|
||||||
)
|
)
|
||||||
return memberChooserObject.generateMember(
|
return memberChooserObject.generateMember(
|
||||||
@@ -321,35 +270,12 @@ internal fun generateFunction(
|
|||||||
mode = if (generateExpect) MemberGenerateMode.EXPECT else MemberGenerateMode.ACTUAL
|
mode = if (generateExpect) MemberGenerateMode.EXPECT else MemberGenerateMode.ACTUAL
|
||||||
).apply {
|
).apply {
|
||||||
repair(generatedClass, descriptor, checker)
|
repair(generatedClass, descriptor, checker)
|
||||||
} as KtFunction
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun generateProperty(
|
private fun CallableMemberDescriptor.checkAccessibility(checker: TypeAccessibilityChecker) {
|
||||||
project: Project,
|
val errors = checker.incorrectTypes(this).ifEmpty { return }
|
||||||
generateExpect: Boolean,
|
throw KotlinTypeInaccessibleException(errors.toSet())
|
||||||
originalProperty: KtNamedDeclaration,
|
|
||||||
descriptor: PropertyDescriptor,
|
|
||||||
generatedClass: KtClassOrObject? = null,
|
|
||||||
outerClasses: List<KtClassOrObject> = emptyList(),
|
|
||||||
checker: TypeAccessibilityChecker
|
|
||||||
): KtProperty {
|
|
||||||
if (generateExpect) {
|
|
||||||
val accessibleClasses = outerClasses + listOfNotNull(generatedClass)
|
|
||||||
descriptor.checkTypeParameterBoundsAccessibility(accessibleClasses)
|
|
||||||
descriptor.type.checkAccessibility(accessibleClasses)
|
|
||||||
}
|
|
||||||
val memberChooserObject = create(
|
|
||||||
originalProperty, descriptor, descriptor,
|
|
||||||
if (generateExpect || descriptor.modality == Modality.ABSTRACT) NO_BODY else EMPTY_OR_TEMPLATE
|
|
||||||
)
|
|
||||||
return memberChooserObject.generateMember(
|
|
||||||
targetClass = generatedClass,
|
|
||||||
copyDoc = true,
|
|
||||||
project = project,
|
|
||||||
mode = if (generateExpect) MemberGenerateMode.EXPECT else MemberGenerateMode.ACTUAL
|
|
||||||
).apply {
|
|
||||||
repair(generatedClass, descriptor, checker)
|
|
||||||
} as KtProperty
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun KtCallableDeclaration.repair(
|
private fun KtCallableDeclaration.repair(
|
||||||
@@ -383,54 +309,9 @@ private fun AnnotationDescriptor.isValidInModule(checker: TypeAccessibilityCheck
|
|||||||
return fqName !in forbiddenAnnotationFqNames && checker.checkAccessibility(type)
|
return fqName !in forbiddenAnnotationFqNames && checker.checkAccessibility(type)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun CallableMemberDescriptor.checkTypeParameterBoundsAccessibility(accessibleClasses: List<KtClassOrObject>) {
|
class KotlinTypeInaccessibleException(fqNames: Collection<FqName?>) : Exception() {
|
||||||
typeParameters.forEach { typeParameter ->
|
override val message: String =
|
||||||
typeParameter.upperBounds.forEach { upperBound ->
|
"${StringUtil.pluralize("Type", fqNames.size)} ${fqNames.joinToString()} is not accessible from common code"
|
||||||
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.platform.isCommon()) {
|
|
||||||
// Common classes are Ok; unfortunately this check does not work correctly for simple (non-expect) classes from common module
|
|
||||||
return
|
|
||||||
}
|
|
||||||
val declaration = DescriptorToSourceUtils.descriptorToDeclaration(classifierDescriptor)
|
|
||||||
if (declaration?.module?.platform?.isCommon() == true) {
|
|
||||||
// Common classes are Ok again
|
|
||||||
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"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun KtNamedDeclaration.isAlwaysActual(): Boolean = safeAs<KtParameter>()?.parent?.parent?.safeAs<KtPrimaryConstructor>()
|
fun KtNamedDeclaration.isAlwaysActual(): Boolean = safeAs<KtParameter>()?.parent?.parent?.safeAs<KtPrimaryConstructor>()
|
||||||
|
|||||||
Reference in New Issue
Block a user