[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:
Pavel Kunyavskiy
2023-07-04 10:42:02 +02:00
committed by Space Team
parent 27043bd8a6
commit 6da3ecceab
20 changed files with 456 additions and 3 deletions
+1
View File
@@ -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]
@@ -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)
@@ -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))
}
}
}
@@ -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))
}
}
}
}
@@ -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) {
@@ -30,6 +30,12 @@ public class DiagnosticsNativeTestGenerated extends AbstractDiagnosticsNativeTes
runTest("compiler/testData/diagnostics/nativeTests/cloneableInNative.kt");
}
@Test
@TestMetadata("forwardDeclarations.kt")
public void testForwardDeclarations() throws Exception {
runTest("compiler/testData/diagnostics/nativeTests/forwardDeclarations.kt");
}
@Test
@TestMetadata("identifiers.kt")
public void testIdentifiers() throws Exception {
@@ -34,6 +34,12 @@ public class FirLightTreeOldFrontendNativeDiagnosticsTestGenerated extends Abstr
runTest("compiler/testData/diagnostics/nativeTests/cloneableInNative.kt");
}
@Test
@TestMetadata("forwardDeclarations.kt")
public void testForwardDeclarations() throws Exception {
runTest("compiler/testData/diagnostics/nativeTests/forwardDeclarations.kt");
}
@Test
@TestMetadata("identifiers.kt")
public void testIdentifiers() throws Exception {
@@ -34,6 +34,12 @@ public class FirPsiOldFrontendNativeDiagnosticsTestGenerated extends AbstractFir
runTest("compiler/testData/diagnostics/nativeTests/cloneableInNative.kt");
}
@Test
@TestMetadata("forwardDeclarations.kt")
public void testForwardDeclarations() throws Exception {
runTest("compiler/testData/diagnostics/nativeTests/forwardDeclarations.kt");
}
@Test
@TestMetadata("identifiers.kt")
public void testIdentifiers() throws Exception {