[K/N] Implement frontend checkers for usages forward declaration type
Forward declaration type doesn't exist in runtime. This restricts its possible usages. ^KT-59764
This commit is contained in:
committed by
Space Team
parent
27043bd8a6
commit
6da3ecceab
@@ -6,6 +6,7 @@ plugins {
|
||||
dependencies {
|
||||
compileOnly(project(":compiler:frontend"))
|
||||
compileOnly(project(":compiler:frontend.java"))
|
||||
compileOnly(project(":core:compiler.common.native"))
|
||||
compileOnly(intellijCore())
|
||||
api(project(":native:kotlin-native-utils"))
|
||||
}
|
||||
|
||||
@@ -5,10 +5,15 @@
|
||||
|
||||
package org.jetbrains.kotlin.descriptors.konan
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
|
||||
import org.jetbrains.kotlin.konan.library.KONAN_STDLIB_NAME
|
||||
import org.jetbrains.kotlin.name.NativeForwardDeclarationKind
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
val NATIVE_STDLIB_MODULE_NAME = Name.special("<$KONAN_STDLIB_NAME>")
|
||||
|
||||
fun ModuleDescriptor.isNativeStdlib() = name == NATIVE_STDLIB_MODULE_NAME
|
||||
fun ClassDescriptor.getForwardDeclarationKindOrNull() =
|
||||
NativeForwardDeclarationKind.packageFqNameToKind[(containingDeclaration as? PackageFragmentDescriptor)?.fqName]
|
||||
+21
@@ -69,6 +69,27 @@ private val DIAGNOSTIC_FACTORY_TO_RENDERER by lazy {
|
||||
ErrorsNative.SUBTYPE_OF_HIDDEN_FROM_OBJC,
|
||||
"Only @HiddenFromObjC declaration can be a subtype of @HiddenFromObjC declaration"
|
||||
)
|
||||
|
||||
put(
|
||||
ErrorsNative.CANNOT_CHECK_FOR_FORWARD_DECLARATION,
|
||||
"Cannot check for forward declaration: ''{0}''",
|
||||
Renderers.RENDER_TYPE
|
||||
)
|
||||
put(ErrorsNative.UNCHECKED_CAST_TO_FORWARD_DECLARATION,
|
||||
"Unchecked cast to forward declaration: ''{0}'' to ''{1}''",
|
||||
Renderers.RENDER_TYPE,
|
||||
Renderers.RENDER_TYPE
|
||||
)
|
||||
put(
|
||||
ErrorsNative.FORWARD_DECLARATION_AS_REIFIED_TYPE_ARGUMENT,
|
||||
"Cannot pass forward declaration ''{0}'' for reified type parameter",
|
||||
Renderers.RENDER_TYPE
|
||||
)
|
||||
put(
|
||||
ErrorsNative.FORWARD_DECLARATION_AS_CLASS_LITERAL,
|
||||
"Can't refer to forward declaration ''{0}'' from class literal",
|
||||
Renderers.RENDER_TYPE
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.diagnostics.*
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtElement
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
|
||||
object ErrorsNative {
|
||||
@JvmField
|
||||
@@ -60,6 +61,14 @@ object ErrorsNative {
|
||||
val INVALID_REFINES_IN_SWIFT_TARGETS = DiagnosticFactory0.create<KtElement>(Severity.ERROR)
|
||||
@JvmField
|
||||
val SUBTYPE_OF_HIDDEN_FROM_OBJC = DiagnosticFactory0.create<KtElement>(Severity.ERROR)
|
||||
@JvmField
|
||||
val CANNOT_CHECK_FOR_FORWARD_DECLARATION = DiagnosticFactory1.create<PsiElement, KotlinType>(Severity.ERROR)
|
||||
@JvmField
|
||||
val UNCHECKED_CAST_TO_FORWARD_DECLARATION = DiagnosticFactory2.create<PsiElement, KotlinType, KotlinType>(Severity.WARNING)
|
||||
@JvmField
|
||||
val FORWARD_DECLARATION_AS_REIFIED_TYPE_ARGUMENT = DiagnosticFactory1.create<PsiElement, KotlinType>(Severity.ERROR)
|
||||
@JvmField
|
||||
val FORWARD_DECLARATION_AS_CLASS_LITERAL = DiagnosticFactory1.create<PsiElement, KotlinType>(Severity.ERROR)
|
||||
|
||||
init {
|
||||
Errors.Initializer.initializeFactoryNames(ErrorsNative::class.java)
|
||||
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.resolve.konan.diagnostics
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.konan.getForwardDeclarationKindOrNull
|
||||
import org.jetbrains.kotlin.psi.KtClassLiteralExpression
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||
import org.jetbrains.kotlin.resolve.calls.checkers.RttiExpressionChecker
|
||||
import org.jetbrains.kotlin.resolve.calls.checkers.RttiExpressionInformation
|
||||
import org.jetbrains.kotlin.resolve.calls.checkers.RttiOperation
|
||||
import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getAllSuperClassifiers
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.expressions.ClassLiteralChecker
|
||||
|
||||
class NativeForwardDeclarationRttiChecker : RttiExpressionChecker, ClassLiteralChecker {
|
||||
override fun check(rttiInformation: RttiExpressionInformation, reportOn: PsiElement, trace: BindingTrace) {
|
||||
val sourceType = rttiInformation.sourceType
|
||||
val targetType = rttiInformation.targetType
|
||||
val targetDescriptor = targetType?.constructor?.declarationDescriptor
|
||||
if (sourceType != null && targetDescriptor is ClassDescriptor) {
|
||||
val kind = targetDescriptor.getForwardDeclarationKindOrNull() ?: return
|
||||
when (rttiInformation.operation) {
|
||||
RttiOperation.IS,
|
||||
RttiOperation.NOT_IS -> trace.report(ErrorsNative.CANNOT_CHECK_FOR_FORWARD_DECLARATION.on(reportOn, targetType))
|
||||
|
||||
RttiOperation.AS,
|
||||
RttiOperation.SAFE_AS -> {
|
||||
// It can make sense to avoid warning if sourceClass is subclass of class with such property,
|
||||
// but for the sake of simplicity, we don't do it now.
|
||||
val sourceDescriptor = sourceType.constructor.declarationDescriptor as? ClassDescriptor
|
||||
val isAllowedCast = sourceDescriptor != null &&
|
||||
sourceDescriptor.name == targetDescriptor.name &&
|
||||
sourceDescriptor.kind == kind.classKind &&
|
||||
sourceDescriptor.getAllSuperClassifiers().any { it.fqNameSafe == kind.matchSuperClassFqName }
|
||||
if (!isAllowedCast) {
|
||||
trace.report(ErrorsNative.UNCHECKED_CAST_TO_FORWARD_DECLARATION.on(reportOn, sourceType, targetType))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun check(expression: KtClassLiteralExpression, type: KotlinType, context: ResolutionContext<*>) {
|
||||
val descriptor = type.constructor.declarationDescriptor as? ClassDescriptor
|
||||
if (descriptor?.getForwardDeclarationKindOrNull() != null) {
|
||||
context.trace.report(ErrorsNative.FORWARD_DECLARATION_AS_CLASS_LITERAL.on(expression, type))
|
||||
}
|
||||
}
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.resolve.konan.diagnostics
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker
|
||||
import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.descriptors.konan.*
|
||||
|
||||
class NativeReifiedForwardDeclarationChecker : CallChecker {
|
||||
override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) {
|
||||
val typeArgumentList = resolvedCall.call.typeArgumentList?.arguments
|
||||
for ((typeParam, typeArg) in resolvedCall.typeArguments) {
|
||||
if (!typeParam.isReified) continue
|
||||
|
||||
val typeArgDescriptor = typeArg.constructor.declarationDescriptor
|
||||
if (typeArgDescriptor is ClassDescriptor && typeArgDescriptor.getForwardDeclarationKindOrNull() != null) {
|
||||
val typeArgumentPsi = if (typeArgumentList != null) {
|
||||
typeArgumentList[typeParam.index].typeReference
|
||||
} else {
|
||||
resolvedCall.call.calleeExpression
|
||||
}
|
||||
|
||||
context.trace.report(ErrorsNative.FORWARD_DECLARATION_AS_REIFIED_TYPE_ARGUMENT.on(typeArgumentPsi!!, typeArg))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
-2
@@ -21,19 +21,21 @@ import org.jetbrains.kotlin.resolve.konan.diagnostics.*
|
||||
object NativePlatformConfigurator : PlatformConfiguratorBase(
|
||||
additionalCallCheckers = listOf(
|
||||
SuperCallWithDefaultArgumentsChecker(),
|
||||
LateinitIntrinsicApplicabilityChecker(isWarningInPre19 = true)
|
||||
LateinitIntrinsicApplicabilityChecker(isWarningInPre19 = true),
|
||||
NativeReifiedForwardDeclarationChecker(),
|
||||
),
|
||||
additionalDeclarationCheckers = listOf(
|
||||
NativeThrowsChecker, NativeSharedImmutableChecker,
|
||||
NativeThreadLocalChecker,
|
||||
NativeObjCNameChecker, NativeObjCNameOverridesChecker,
|
||||
NativeObjCRefinementChecker, NativeObjCRefinementAnnotationChecker,
|
||||
NativeObjCRefinementOverridesChecker, NativeHiddenFromObjCInheritanceChecker
|
||||
NativeObjCRefinementOverridesChecker, NativeHiddenFromObjCInheritanceChecker,
|
||||
)
|
||||
) {
|
||||
override fun configureModuleComponents(container: StorageComponentContainer) {
|
||||
container.useInstance(NativeInliningRule)
|
||||
container.useImpl<NativeIdentifierChecker>()
|
||||
container.useImpl<NativeForwardDeclarationRttiChecker>()
|
||||
}
|
||||
|
||||
override fun configureModuleDependentCheckers(container: StorageComponentContainer) {
|
||||
|
||||
Reference in New Issue
Block a user