[JS IR] Control an inheritance of non-external entity from external
Add a special annotation @JsExternalInheritorsOnly for marking external interfaces and classes. The marked interface or class can’t be a parent for non external interfaces, classes or objects. ^KT-57423 Fixed
This commit is contained in:
committed by
Space Team
parent
6e7b078873
commit
4813b659ab
+5
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.fir.PrivateForInline
|
||||
import org.jetbrains.kotlin.fir.checkers.generator.diagnostics.model.DiagnosticList
|
||||
import org.jetbrains.kotlin.fir.checkers.generator.diagnostics.model.PositioningStrategy
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
@@ -94,6 +95,10 @@ object JS_DIAGNOSTICS_LIST : DiagnosticList("FirJsErrors") {
|
||||
parameter<ConeKotlinType>("targetType")
|
||||
}
|
||||
val EXTERNAL_INTERFACE_AS_CLASS_LITERAL by error<KtElement>()
|
||||
val JS_EXTERNAL_INHERITORS_ONLY by error<KtDeclaration>(PositioningStrategy.DECLARATION_SIGNATURE_OR_DEFAULT) {
|
||||
parameter<FirClassLikeSymbol<*>>("parent")
|
||||
parameter<FirClassLikeSymbol<*>>("kid")
|
||||
}
|
||||
}
|
||||
|
||||
val EXPORT by object : DiagnosticGroup("Export") {
|
||||
|
||||
+2
@@ -11,6 +11,7 @@ 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.symbols.impl.FirCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||
import org.jetbrains.kotlin.psi.KtAnonymousInitializer
|
||||
@@ -78,6 +79,7 @@ object FirJsErrors {
|
||||
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 JS_EXTERNAL_INHERITORS_ONLY by error2<KtDeclaration, FirClassLikeSymbol<*>, FirClassLikeSymbol<*>>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE_OR_DEFAULT)
|
||||
|
||||
// Export
|
||||
val NESTED_JS_EXPORT by error0<KtElement>()
|
||||
|
||||
+7
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors.IMPLEMENTING
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors.INLINE_CLASS_IN_EXTERNAL_DECLARATION
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors.INLINE_CLASS_IN_EXTERNAL_DECLARATION_WARNING
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors.ENUM_CLASS_IN_EXTERNAL_DECLARATION_WARNING
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors.JS_EXTERNAL_INHERITORS_ONLY
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors.INLINE_EXTERNAL_DECLARATION
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors.JS_MODULE_PROHIBITED_ON_NON_NATIVE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors.JS_MODULE_PROHIBITED_ON_VAR
|
||||
@@ -153,6 +154,12 @@ object FirJsErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
|
||||
"Can''t put non-external declarations in file marked with {0} annotation",
|
||||
FirDiagnosticRenderers.RENDER_TYPE
|
||||
)
|
||||
map.put(
|
||||
JS_EXTERNAL_INHERITORS_ONLY,
|
||||
"External {0} can''t be a parent of non-external {1}",
|
||||
FirDiagnosticRenderers.RENDER_CLASS_OR_OBJECT_NAME,
|
||||
FirDiagnosticRenderers.RENDER_CLASS_OR_OBJECT_NAME
|
||||
)
|
||||
map.put(JS_NAME_PROHIBITED_FOR_EXTENSION_PROPERTY, "@JsName is prohibited for extension properties")
|
||||
map.put(JS_NAME_IS_NOT_ON_ALL_ACCESSORS, "@JsName should be on all the property accessors")
|
||||
map.put(JS_NAME_PROHIBITED_FOR_NAMED_NATIVE, "@JsName is prohibited for external declaration with explicit name")
|
||||
|
||||
+1
@@ -36,6 +36,7 @@ object JsDeclarationCheckers : DeclarationCheckers() {
|
||||
FirJsMultipleInheritanceChecker,
|
||||
FirJsDynamicDeclarationChecker,
|
||||
FirJsInheritanceClassChecker,
|
||||
FirJsExternalInheritorOnlyChecker
|
||||
)
|
||||
|
||||
override val simpleFunctionCheckers: Set<FirSimpleFunctionChecker>
|
||||
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* 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.js.checkers.declaration
|
||||
|
||||
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.js.FirJsErrors
|
||||
import org.jetbrains.kotlin.fir.analysis.js.checkers.isEffectivelyExternal
|
||||
import org.jetbrains.kotlin.fir.declarations.FirClass
|
||||
import org.jetbrains.kotlin.fir.declarations.hasAnnotation
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.superConeTypes
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
|
||||
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
|
||||
import org.jetbrains.kotlin.fir.types.coneTypeSafe
|
||||
import org.jetbrains.kotlin.fir.types.toRegularClassSymbol
|
||||
import org.jetbrains.kotlin.name.JsStandardClassIds.Annotations.JsExternalInheritorsOnly
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.popLast
|
||||
|
||||
object FirJsExternalInheritorOnlyChecker : FirClassChecker() {
|
||||
private fun FirClass.forEachParents(context: CheckerContext, f: (FirRegularClassSymbol) -> Unit) {
|
||||
val todo = superConeTypes.toMutableList()
|
||||
val done = hashSetOf<FirRegularClassSymbol>()
|
||||
|
||||
while (todo.isNotEmpty()) {
|
||||
val classSymbol = todo.popLast().toRegularClassSymbol(context.session) ?: continue
|
||||
if (done.add(classSymbol)) {
|
||||
f(classSymbol)
|
||||
classSymbol.resolvedSuperTypeRefs.mapNotNullTo(todo) { it.type as? ConeClassLikeType }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
if (!declaration.symbol.isEffectivelyExternal(context)) {
|
||||
declaration.forEachParents(context) { parent ->
|
||||
if (parent.hasAnnotation(JsExternalInheritorsOnly, context.session)) {
|
||||
reporter.reportOn(
|
||||
declaration.source,
|
||||
FirJsErrors.JS_EXTERNAL_INHERITORS_ONLY,
|
||||
parent,
|
||||
declaration.symbol,
|
||||
context
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user