[K/N] Implement FirNativeObjCOutletChecker and FirNativeObjCActionChecker
^KT-61564
This commit is contained in:
committed by
Space Team
parent
08bc0a6bd0
commit
c5aed2b094
+15
@@ -79,5 +79,20 @@ object NATIVE_DIAGNOSTICS_LIST : DiagnosticList("FirNativeErrors") {
|
||||
val FORWARD_DECLARATION_AS_CLASS_LITERAL by error<KtElement> {
|
||||
parameter<ConeKotlinType>("type")
|
||||
}
|
||||
val TWO_OR_LESS_PARAMETERS_ARE_SUPPORTED_HERE by error<KtElement>()
|
||||
val PROPERTY_MUST_BE_VAR by error<KtElement>() {
|
||||
parameter<FqName>("annotationName")
|
||||
}
|
||||
val MUST_NOT_HAVE_EXTENSION_RECEIVER by error<KtElement> {
|
||||
parameter<String>("annotationKind")
|
||||
}
|
||||
val MUST_BE_OBJC_OBJECT_TYPE by error<KtElement>() {
|
||||
parameter<String>("annotationName")
|
||||
parameter<ConeKotlinType>("unexpectedType")
|
||||
}
|
||||
val MUST_BE_UNIT_TYPE by error<KtElement>() {
|
||||
parameter<String>("annotationKind")
|
||||
parameter<ConeKotlinType>("unexpectedType")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ dependencies {
|
||||
*/
|
||||
implementation(project(":compiler:frontend"))
|
||||
implementation(project(":compiler:psi"))
|
||||
implementation(project(":compiler:fir:native"))
|
||||
|
||||
compileOnly(project(":core:compiler.common.native"))
|
||||
compileOnly(commonDependency("org.jetbrains.kotlin:kotlin-reflect")) { isTransitive = false }
|
||||
|
||||
+5
@@ -54,6 +54,11 @@ object FirNativeErrors {
|
||||
val UNCHECKED_CAST_TO_FORWARD_DECLARATION: KtDiagnosticFactory2<ConeKotlinType, ConeKotlinType> by warning2<KtElement, ConeKotlinType, ConeKotlinType>()
|
||||
val FORWARD_DECLARATION_AS_REIFIED_TYPE_ARGUMENT: KtDiagnosticFactory1<ConeKotlinType> by error1<KtElement, ConeKotlinType>()
|
||||
val FORWARD_DECLARATION_AS_CLASS_LITERAL: KtDiagnosticFactory1<ConeKotlinType> by error1<KtElement, ConeKotlinType>()
|
||||
val TWO_OR_LESS_PARAMETERS_ARE_SUPPORTED_HERE: KtDiagnosticFactory0 by error0<KtElement>()
|
||||
val PROPERTY_MUST_BE_VAR: KtDiagnosticFactory1<FqName> by error1<KtElement, FqName>()
|
||||
val MUST_NOT_HAVE_EXTENSION_RECEIVER: KtDiagnosticFactory1<String> by error1<KtElement, String>()
|
||||
val MUST_BE_OBJC_OBJECT_TYPE: KtDiagnosticFactory2<String, ConeKotlinType> by error2<KtElement, String, ConeKotlinType>()
|
||||
val MUST_BE_UNIT_TYPE: KtDiagnosticFactory2<String, ConeKotlinType> by error2<KtElement, String, ConeKotlinType>()
|
||||
|
||||
init {
|
||||
RootDiagnosticRendererFactory.registerFactory(FirNativeErrorsDefaultMessages)
|
||||
|
||||
+21
-2
@@ -8,7 +8,6 @@ package org.jetbrains.kotlin.fir.analysis.diagnostics.native
|
||||
import org.jetbrains.kotlin.diagnostics.KtDiagnosticFactoryToRendererMap
|
||||
import org.jetbrains.kotlin.diagnostics.KtDiagnosticRenderers.TO_STRING
|
||||
import org.jetbrains.kotlin.diagnostics.rendering.BaseDiagnosticRendererFactory
|
||||
import org.jetbrains.kotlin.diagnostics.rendering.Renderers
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.SYMBOL
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.SYMBOLS
|
||||
@@ -34,10 +33,15 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.INVA
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.INVALID_REFINES_IN_SWIFT_TARGETS
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.MISSING_EXACT_OBJC_NAME
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.MISSING_EXCEPTION_IN_THROWS_ON_SUSPEND
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.REDUNDANT_SWIFT_REFINEMENT
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.MUST_BE_OBJC_OBJECT_TYPE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.MUST_BE_UNIT_TYPE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.MUST_NOT_HAVE_EXTENSION_RECEIVER
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.NON_LITERAL_OBJC_NAME_ARG
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.PROPERTY_MUST_BE_VAR
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.REDUNDANT_SWIFT_REFINEMENT
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.SUBTYPE_OF_HIDDEN_FROM_OBJC
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.THROWS_LIST_EMPTY
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.TWO_OR_LESS_PARAMETERS_ARE_SUPPORTED_HERE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.UNCHECKED_CAST_TO_FORWARD_DECLARATION
|
||||
|
||||
object FirNativeErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
|
||||
@@ -108,5 +112,20 @@ object FirNativeErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
|
||||
"Cannot refer to forward declaration ''{0}'' from class literal.",
|
||||
FirDiagnosticRenderers.RENDER_TYPE
|
||||
)
|
||||
map.put(TWO_OR_LESS_PARAMETERS_ARE_SUPPORTED_HERE, "Only 0, 1 or 2 parameters are supported here")
|
||||
map.put(PROPERTY_MUST_BE_VAR, "@{0} property must be var", TO_STRING)
|
||||
map.put(MUST_NOT_HAVE_EXTENSION_RECEIVER, "{0} must not have extension receiver", TO_STRING)
|
||||
map.put(
|
||||
MUST_BE_OBJC_OBJECT_TYPE,
|
||||
"Unexpected {0}: {1}\nOnly Objective-C object types are supported here",
|
||||
TO_STRING,
|
||||
FirDiagnosticRenderers.RENDER_TYPE
|
||||
)
|
||||
map.put(
|
||||
MUST_BE_UNIT_TYPE,
|
||||
"Unexpected {0}: {1}\nOnly \"Unit\" is supported here",
|
||||
TO_STRING,
|
||||
FirDiagnosticRenderers.RENDER_TYPE
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright 2010-2022 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.fir.analysis.native.checkers
|
||||
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirClassChecker
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.MUST_BE_OBJC_OBJECT_TYPE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.MUST_BE_UNIT_TYPE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors.MUST_NOT_HAVE_EXTENSION_RECEIVER
|
||||
import org.jetbrains.kotlin.fir.backend.native.interop.isKotlinObjCClass
|
||||
import org.jetbrains.kotlin.fir.backend.native.interop.isObjCObjectType
|
||||
import org.jetbrains.kotlin.fir.declarations.FirClass
|
||||
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
|
||||
import org.jetbrains.kotlin.fir.declarations.hasAnnotation
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isExpect
|
||||
import org.jetbrains.kotlin.fir.types.UnexpandedTypeCheck
|
||||
import org.jetbrains.kotlin.fir.types.coneType
|
||||
import org.jetbrains.kotlin.fir.types.isUnit
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
|
||||
object FirNativeObjCActionChecker : FirClassChecker() {
|
||||
// Copy/pasted from InteropFqNames.objCAction, since module `kotlin-native:backend.native` cannot be imported here for now.
|
||||
val objCActionFqName = FqName("kotlinx.cinterop.ObjCAction")
|
||||
|
||||
@OptIn(UnexpandedTypeCheck::class)
|
||||
override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
val session = context.session
|
||||
|
||||
fun checkCanGenerateFunctionImp(function: FirSimpleFunction) {
|
||||
if (function.valueParameters.size > 2)
|
||||
reporter.reportOn(function.source, FirNativeErrors.TWO_OR_LESS_PARAMETERS_ARE_SUPPORTED_HERE, context)
|
||||
}
|
||||
|
||||
fun checkCanGenerateActionImp(function: FirSimpleFunction) {
|
||||
val action = "@$objCActionFqName"
|
||||
|
||||
function.receiverParameter?.let {
|
||||
reporter.reportOn(it.source, MUST_NOT_HAVE_EXTENSION_RECEIVER, "$action method", context)
|
||||
}
|
||||
|
||||
function.valueParameters.forEach {
|
||||
val kotlinType = it.returnTypeRef
|
||||
if (!kotlinType.isObjCObjectType(session))
|
||||
reporter.reportOn(it.source, MUST_BE_OBJC_OBJECT_TYPE, "$action method parameter type", kotlinType.coneType, context)
|
||||
}
|
||||
|
||||
val returnType = function.returnTypeRef
|
||||
if (!returnType.isUnit)
|
||||
reporter.reportOn(function.source, MUST_BE_UNIT_TYPE, "$action method return type", returnType.coneType, context)
|
||||
|
||||
checkCanGenerateFunctionImp(function)
|
||||
}
|
||||
|
||||
fun checkKotlinObjCClass(firClass: FirClass) {
|
||||
for (decl in firClass.declarations) {
|
||||
if (decl is FirSimpleFunction && decl.annotations.hasAnnotation(ClassId.topLevel(objCActionFqName), session))
|
||||
checkCanGenerateActionImp(decl)
|
||||
}
|
||||
}
|
||||
|
||||
if (!declaration.isExpect && declaration.symbol.isKotlinObjCClass(context.session)) {
|
||||
checkKotlinObjCClass(declaration)
|
||||
}
|
||||
}
|
||||
}
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright 2010-2022 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.fir.analysis.native.checkers
|
||||
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirClassChecker
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.native.FirNativeErrors
|
||||
import org.jetbrains.kotlin.fir.backend.native.interop.isKotlinObjCClass
|
||||
import org.jetbrains.kotlin.fir.backend.native.interop.isObjCObjectType
|
||||
import org.jetbrains.kotlin.fir.declarations.FirClass
|
||||
import org.jetbrains.kotlin.fir.declarations.FirProperty
|
||||
import org.jetbrains.kotlin.fir.declarations.FirPropertyAccessor
|
||||
import org.jetbrains.kotlin.fir.declarations.hasAnnotation
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isExpect
|
||||
import org.jetbrains.kotlin.fir.types.coneType
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
|
||||
object FirNativeObjCOutletChecker : FirClassChecker() {
|
||||
// Copy/pasted from InteropFqNames.objCOutlet, since module `kotlin-native:backend.native` cannot be imported here for now.
|
||||
val objCOutletFqName = FqName("kotlinx.cinterop.ObjCOutlet")
|
||||
|
||||
override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
val session = context.session
|
||||
|
||||
fun checkCanGenerateFunctionImp(setter: FirPropertyAccessor) {
|
||||
if (setter.valueParameters.size > 2)
|
||||
reporter.reportOn(setter.source, FirNativeErrors.TWO_OR_LESS_PARAMETERS_ARE_SUPPORTED_HERE, context)
|
||||
}
|
||||
|
||||
fun checkCanGenerateOutletSetterImp(property: FirProperty) {
|
||||
if (!property.isVar) {
|
||||
reporter.reportOn(property.source, FirNativeErrors.PROPERTY_MUST_BE_VAR, objCOutletFqName, context)
|
||||
return
|
||||
}
|
||||
|
||||
property.receiverParameter?.let {
|
||||
reporter.reportOn(it.source, FirNativeErrors.MUST_NOT_HAVE_EXTENSION_RECEIVER, "@$objCOutletFqName", context)
|
||||
}
|
||||
|
||||
val type = property.returnTypeRef
|
||||
if (!type.isObjCObjectType(session))
|
||||
reporter.reportOn(
|
||||
property.returnTypeRef.source,
|
||||
FirNativeErrors.MUST_BE_OBJC_OBJECT_TYPE,
|
||||
"@$objCOutletFqName type",
|
||||
type.coneType,
|
||||
context
|
||||
)
|
||||
|
||||
checkCanGenerateFunctionImp(property.setter!!)
|
||||
}
|
||||
|
||||
fun checkKotlinObjCClass(firClass: FirClass) {
|
||||
for (decl in firClass.declarations) {
|
||||
if (decl is FirProperty && decl.annotations.hasAnnotation(ClassId.topLevel(objCOutletFqName), session))
|
||||
checkCanGenerateOutletSetterImp(decl)
|
||||
}
|
||||
}
|
||||
|
||||
if (!declaration.isExpect && declaration.symbol.isKotlinObjCClass(context.session)) {
|
||||
checkKotlinObjCClass(declaration)
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
-1
@@ -25,7 +25,9 @@ object NativeDeclarationCheckers : DeclarationCheckers() {
|
||||
override val classCheckers: Set<FirClassChecker>
|
||||
get() = setOf(
|
||||
FirNativeObjCRefinementOverridesChecker,
|
||||
FirNativeObjCNameOverridesChecker
|
||||
FirNativeObjCNameOverridesChecker,
|
||||
FirNativeObjCOutletChecker,
|
||||
FirNativeObjCActionChecker,
|
||||
)
|
||||
|
||||
override val regularClassCheckers: Set<FirRegularClassChecker>
|
||||
|
||||
+5
@@ -667,6 +667,11 @@ val FIR_NON_SUPPRESSIBLE_ERROR_NAMES: Set<String> = setOf(
|
||||
"CANNOT_CHECK_FOR_FORWARD_DECLARATION",
|
||||
"FORWARD_DECLARATION_AS_REIFIED_TYPE_ARGUMENT",
|
||||
"FORWARD_DECLARATION_AS_CLASS_LITERAL",
|
||||
"TWO_OR_LESS_PARAMETERS_ARE_SUPPORTED_HERE",
|
||||
"PROPERTY_MUST_BE_VAR",
|
||||
"MUST_NOT_HAVE_EXTENSION_RECEIVER",
|
||||
"MUST_BE_OBJC_OBJECT_TYPE",
|
||||
"MUST_BE_UNIT_TYPE",
|
||||
"NESTED_EXTERNAL_DECLARATION",
|
||||
"WRONG_EXTERNAL_DECLARATION",
|
||||
"NESTED_CLASS_IN_EXTERNAL_INTERFACE",
|
||||
|
||||
+9
-4
@@ -10,12 +10,9 @@ import org.jetbrains.kotlin.fir.containingClassLookupTag
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
|
||||
import org.jetbrains.kotlin.fir.expressions.FirConstExpression
|
||||
import org.jetbrains.kotlin.fir.resolve.ScopeSession
|
||||
import org.jetbrains.kotlin.fir.resolve.getContainingClass
|
||||
import org.jetbrains.kotlin.fir.resolve.getContainingDeclaration
|
||||
import org.jetbrains.kotlin.fir.resolve.*
|
||||
import org.jetbrains.kotlin.fir.resolve.providers.toSymbol
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
||||
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
||||
import org.jetbrains.kotlin.fir.scopes.getDirectOverriddenFunctions
|
||||
import org.jetbrains.kotlin.fir.scopes.processAllFunctions
|
||||
import org.jetbrains.kotlin.fir.scopes.scopeForClass
|
||||
@@ -24,6 +21,7 @@ import org.jetbrains.kotlin.fir.symbols.SymbolInternals
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.classId
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.name.NativeStandardInteropNames
|
||||
@@ -154,3 +152,10 @@ internal fun FirClassSymbol<*>.isExternalObjCClass(session: FirSession): Boolean
|
||||
fun FirClassSymbol<*>.parentsWithSelf(session: FirSession): Sequence<FirClassLikeDeclaration> {
|
||||
return generateSequence<FirClassLikeDeclaration>(fir) { it.getContainingDeclaration(session) }
|
||||
}
|
||||
|
||||
fun FirClassSymbol<*>.isKotlinObjCClass(session: FirSession): Boolean = isObjCClass(session) && !isExternalObjCClass(session)
|
||||
|
||||
fun FirTypeRef.isObjCObjectType(session: FirSession): Boolean {
|
||||
val symbol = firClassLike(session)?.symbol
|
||||
return symbol is FirClassSymbol && symbol.isObjCClass(session)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user