[Wasm] Move external RTT checkers to web.common and reuse in Wasm

#KT-56849
This commit is contained in:
Svyatoslav Kuzmich
2023-11-21 14:29:28 +01:00
committed by Space Team
parent d219d5380b
commit cf3b293072
24 changed files with 360 additions and 121 deletions
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.diagnostics.*
import org.jetbrains.kotlin.diagnostics.SourceElementPositioningStrategies
import org.jetbrains.kotlin.diagnostics.rendering.RootDiagnosticRendererFactory
import org.jetbrains.kotlin.fir.analysis.diagnostics.*
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.psi.KtAnonymousInitializer
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtElement
@@ -35,6 +36,10 @@ object FirWebCommonErrors {
val WRONG_BODY_OF_EXTERNAL_DECLARATION by error0<KtElement>()
val WRONG_INITIALIZER_OF_EXTERNAL_DECLARATION by error0<KtElement>()
val WRONG_DEFAULT_VALUE_FOR_EXTERNAL_FUN_PARAMETER by error0<KtElement>()
val CANNOT_CHECK_FOR_EXTERNAL_INTERFACE by error1<KtElement, ConeKotlinType>()
val UNCHECKED_CAST_TO_EXTERNAL_INTERFACE by warning2<KtElement, ConeKotlinType, ConeKotlinType>()
val EXTERNAL_INTERFACE_AS_CLASS_LITERAL by error0<KtElement>()
val EXTERNAL_INTERFACE_AS_REIFIED_TYPE_ARGUMENT by error1<KtElement, ConeKotlinType>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE_OR_DEFAULT)
// Export
val NESTED_JS_EXPORT by error0<KtElement>()
@@ -8,16 +8,21 @@ package org.jetbrains.kotlin.fir.analysis.diagnostics.web.common
import org.jetbrains.kotlin.diagnostics.KtDiagnosticFactoryToRendererMap
import org.jetbrains.kotlin.diagnostics.rendering.BaseDiagnosticRendererFactory
import org.jetbrains.kotlin.diagnostics.rendering.CommonRenderers
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers
import org.jetbrains.kotlin.fir.analysis.diagnostics.web.common.FirWebCommonErrors.CANNOT_CHECK_FOR_EXTERNAL_INTERFACE
import org.jetbrains.kotlin.fir.analysis.diagnostics.web.common.FirWebCommonErrors.EXTERNAL_ANONYMOUS_INITIALIZER
import org.jetbrains.kotlin.fir.analysis.diagnostics.web.common.FirWebCommonErrors.EXTERNAL_CLASS_CONSTRUCTOR_PROPERTY_PARAMETER
import org.jetbrains.kotlin.fir.analysis.diagnostics.web.common.FirWebCommonErrors.EXTERNAL_DELEGATED_CONSTRUCTOR_CALL
import org.jetbrains.kotlin.fir.analysis.diagnostics.web.common.FirWebCommonErrors.EXTERNAL_DELEGATION
import org.jetbrains.kotlin.fir.analysis.diagnostics.web.common.FirWebCommonErrors.EXTERNAL_INTERFACE_AS_CLASS_LITERAL
import org.jetbrains.kotlin.fir.analysis.diagnostics.web.common.FirWebCommonErrors.EXTERNAL_INTERFACE_AS_REIFIED_TYPE_ARGUMENT
import org.jetbrains.kotlin.fir.analysis.diagnostics.web.common.FirWebCommonErrors.INLINE_EXTERNAL_DECLARATION
import org.jetbrains.kotlin.fir.analysis.diagnostics.web.common.FirWebCommonErrors.JSCODE_ARGUMENT_NON_CONST_EXPRESSION
import org.jetbrains.kotlin.fir.analysis.diagnostics.web.common.FirWebCommonErrors.NESTED_CLASS_IN_EXTERNAL_INTERFACE
import org.jetbrains.kotlin.fir.analysis.diagnostics.web.common.FirWebCommonErrors.NESTED_EXTERNAL_DECLARATION
import org.jetbrains.kotlin.fir.analysis.diagnostics.web.common.FirWebCommonErrors.NESTED_JS_EXPORT
import org.jetbrains.kotlin.fir.analysis.diagnostics.web.common.FirWebCommonErrors.NON_ABSTRACT_MEMBER_OF_EXTERNAL_INTERFACE
import org.jetbrains.kotlin.fir.analysis.diagnostics.web.common.FirWebCommonErrors.UNCHECKED_CAST_TO_EXTERNAL_INTERFACE
import org.jetbrains.kotlin.fir.analysis.diagnostics.web.common.FirWebCommonErrors.WRONG_BODY_OF_EXTERNAL_DECLARATION
import org.jetbrains.kotlin.fir.analysis.diagnostics.web.common.FirWebCommonErrors.WRONG_DEFAULT_VALUE_FOR_EXTERNAL_FUN_PARAMETER
import org.jetbrains.kotlin.fir.analysis.diagnostics.web.common.FirWebCommonErrors.WRONG_EXTERNAL_DECLARATION
@@ -49,6 +54,24 @@ object FirWebCommonErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
WRONG_DEFAULT_VALUE_FOR_EXTERNAL_FUN_PARAMETER,
"Wrong default value for parameter of external function. Must be ' = definedExternally'."
)
map.put(
CANNOT_CHECK_FOR_EXTERNAL_INTERFACE,
"Cannot check for external interface: ''{0}''",
FirDiagnosticRenderers.RENDER_TYPE,
)
map.put(
UNCHECKED_CAST_TO_EXTERNAL_INTERFACE,
"Unchecked cast to external interface: ''{0}'' to ''{1}''.",
FirDiagnosticRenderers.RENDER_TYPE,
FirDiagnosticRenderers.RENDER_TYPE,
)
map.put(EXTERNAL_INTERFACE_AS_CLASS_LITERAL, "Cannot refer to external interface from class literal.")
map.put(
EXTERNAL_INTERFACE_AS_REIFIED_TYPE_ARGUMENT,
"Cannot pass external interface ''{0}'' for reified type parameter.",
FirDiagnosticRenderers.RENDER_TYPE
)
map.put(NESTED_JS_EXPORT, "'@JsExport' is only allowed on files and top-level declarations.")
@@ -0,0 +1,13 @@
/*
* 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.fir.analysis.web.common.checkers
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
abstract class FirAbstractWebCheckerUtils {
abstract fun isNativeOrExternalInterface(symbol: FirBasedSymbol<*>, session: FirSession): Boolean
}
@@ -0,0 +1,68 @@
/*
* 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.fir.analysis.web.common.checkers.expression
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.expression.FirBasicExpressionChecker
import org.jetbrains.kotlin.fir.analysis.checkers.toRegularClassSymbol
import org.jetbrains.kotlin.fir.analysis.diagnostics.web.common.FirWebCommonErrors
import org.jetbrains.kotlin.fir.analysis.web.common.checkers.FirAbstractWebCheckerUtils
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.fir.types.resolvedType
import org.jetbrains.kotlin.fir.types.toRegularClassSymbol
abstract class FirAbstractNativeRttiChecker(
private val webCheckerUtils: FirAbstractWebCheckerUtils
) : FirBasicExpressionChecker() {
override fun check(expression: FirStatement, context: CheckerContext, reporter: DiagnosticReporter) {
when (expression) {
is FirGetClassCall -> checkGetClassCall(expression, context, reporter)
is FirTypeOperatorCall -> checkTypeOperatorCall(expression, context, reporter)
else -> {}
}
}
private fun checkGetClassCall(expression: FirGetClassCall, context: CheckerContext, reporter: DiagnosticReporter) {
val declarationToCheck = expression.argument.resolvedType.toRegularClassSymbol(context.session) ?: return
if (expression.arguments.firstOrNull() !is FirResolvedQualifier) {
return
}
if (webCheckerUtils.isNativeOrExternalInterface(declarationToCheck, context.session)) {
reporter.reportOn(expression.source, FirWebCommonErrors.EXTERNAL_INTERFACE_AS_CLASS_LITERAL, context)
}
}
private fun checkTypeOperatorCall(expression: FirTypeOperatorCall, context: CheckerContext, reporter: DiagnosticReporter) {
val targetTypeRef = expression.conversionTypeRef
val declarationToCheck = targetTypeRef.toRegularClassSymbol(context.session) ?: return
if (!webCheckerUtils.isNativeOrExternalInterface(declarationToCheck, context.session)) {
return
}
when (expression.operation) {
FirOperation.AS, FirOperation.SAFE_AS -> reporter.reportOn(
expression.source,
FirWebCommonErrors.UNCHECKED_CAST_TO_EXTERNAL_INTERFACE,
expression.argument.resolvedType,
targetTypeRef.coneType,
context,
)
FirOperation.IS, FirOperation.NOT_IS -> reporter.reportOn(
expression.source,
FirWebCommonErrors.CANNOT_CHECK_FOR_EXTERNAL_INTERFACE,
targetTypeRef.coneType,
context,
)
else -> {}
}
}
}
@@ -0,0 +1,34 @@
/*
* 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.fir.analysis.web.common.checkers.expression
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.expression.FirFunctionCallChecker
import org.jetbrains.kotlin.fir.analysis.diagnostics.web.common.FirWebCommonErrors
import org.jetbrains.kotlin.fir.analysis.web.common.checkers.FirAbstractWebCheckerUtils
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
import org.jetbrains.kotlin.fir.expressions.forAllReifiedTypeParameters
import org.jetbrains.kotlin.fir.types.toSymbol
abstract class FirAbstractReifiedExternalChecker(
private val webCheckerUtils: FirAbstractWebCheckerUtils
) : FirFunctionCallChecker() {
override fun check(expression: FirFunctionCall, context: CheckerContext, reporter: DiagnosticReporter) {
expression.forAllReifiedTypeParameters { type, typeArgument ->
val typeSymbol = type.toSymbol(context.session)
if (typeSymbol != null && webCheckerUtils.isNativeOrExternalInterface(typeSymbol, context.session)) {
reporter.reportOn(
typeArgument.source ?: expression.source,
FirWebCommonErrors.EXTERNAL_INTERFACE_AS_REIFIED_TYPE_ARGUMENT,
type,
context
)
}
}
}
}