[FIR JS] Implement FirJsExportDeclarationChecker
This commit is contained in:
+10
@@ -98,6 +98,16 @@ object JS_DIAGNOSTICS_LIST : DiagnosticList("FirJsErrors") {
|
||||
|
||||
val EXPORT by object : DiagnosticGroup("Export") {
|
||||
val NESTED_JS_EXPORT by error<KtElement>()
|
||||
val WRONG_EXPORTED_DECLARATION by error<KtElement>(PositioningStrategy.DECLARATION_SIGNATURE_OR_DEFAULT) {
|
||||
parameter<String>("kind")
|
||||
}
|
||||
val NON_EXPORTABLE_TYPE by warning<KtElement>(PositioningStrategy.DECLARATION_SIGNATURE_OR_DEFAULT) {
|
||||
parameter<String>("kind")
|
||||
parameter<ConeKotlinType>("type")
|
||||
}
|
||||
val NON_CONSUMABLE_EXPORTED_IDENTIFIER by warning<KtElement>(PositioningStrategy.DEFAULT) {
|
||||
parameter<String>("name")
|
||||
}
|
||||
}
|
||||
|
||||
val DYNAMICS by object : DiagnosticGroup("Dynamics") {
|
||||
|
||||
@@ -7,6 +7,7 @@ plugins {
|
||||
|
||||
dependencies {
|
||||
api(project(":core:compiler.common.js"))
|
||||
api(project(":js:js.ast"))
|
||||
api(project(":compiler:fir:checkers"))
|
||||
|
||||
/*
|
||||
|
||||
+3
@@ -81,6 +81,9 @@ object FirJsErrors {
|
||||
|
||||
// Export
|
||||
val NESTED_JS_EXPORT by error0<KtElement>()
|
||||
val WRONG_EXPORTED_DECLARATION by error1<KtElement, String>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE_OR_DEFAULT)
|
||||
val NON_EXPORTABLE_TYPE by warning2<KtElement, String, ConeKotlinType>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE_OR_DEFAULT)
|
||||
val NON_CONSUMABLE_EXPORTED_IDENTIFIER by warning1<KtElement, String>()
|
||||
|
||||
// Dynamics
|
||||
val DELEGATION_BY_DYNAMIC by error0<KtElement>()
|
||||
|
||||
+15
@@ -46,6 +46,8 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors.NESTED_CLASS
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors.NESTED_EXTERNAL_DECLARATION
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors.NESTED_JS_EXPORT
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors.NON_ABSTRACT_MEMBER_OF_EXTERNAL_INTERFACE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors.NON_CONSUMABLE_EXPORTED_IDENTIFIER
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors.NON_EXPORTABLE_TYPE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors.NON_EXTERNAL_DECLARATION_IN_INAPPROPRIATE_FILE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors.OVERRIDING_EXTERNAL_FUN_WITH_OPTIONAL_PARAMS
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors.OVERRIDING_EXTERNAL_FUN_WITH_OPTIONAL_PARAMS_WITH_FAKE
|
||||
@@ -54,6 +56,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors.RUNTIME_ANNO
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors.UNCHECKED_CAST_TO_EXTERNAL_INTERFACE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors.WRONG_BODY_OF_EXTERNAL_DECLARATION
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors.WRONG_DEFAULT_VALUE_FOR_EXTERNAL_FUN_PARAMETER
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors.WRONG_EXPORTED_DECLARATION
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors.WRONG_EXTERNAL_DECLARATION
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors.WRONG_INITIALIZER_OF_EXTERNAL_DECLARATION
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors.WRONG_JS_QUALIFIER
|
||||
@@ -169,6 +172,18 @@ object FirJsErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
|
||||
)
|
||||
map.put(EXTERNAL_INTERFACE_AS_CLASS_LITERAL, "Can't refer to external interface from class literal")
|
||||
map.put(NESTED_JS_EXPORT, "@JsExport is only allowed on files and top-level declarations")
|
||||
map.put(WRONG_EXPORTED_DECLARATION, "Declaration of such kind ({0}) can''t be exported to JS", CommonRenderers.STRING)
|
||||
map.put(
|
||||
NON_EXPORTABLE_TYPE,
|
||||
"Exported declaration uses non-exportable {0} type: {1}",
|
||||
CommonRenderers.STRING,
|
||||
FirDiagnosticRenderers.RENDER_TYPE,
|
||||
)
|
||||
map.put(
|
||||
NON_CONSUMABLE_EXPORTED_IDENTIFIER,
|
||||
"Exported declaration contains non-consumable identifier '${0}', that can't be represented inside TS definitions and ESM",
|
||||
CommonRenderers.STRING,
|
||||
)
|
||||
|
||||
map.checkMissingMessages(FirJsErrors)
|
||||
}
|
||||
|
||||
+40
-6
@@ -8,22 +8,22 @@
|
||||
package org.jetbrains.kotlin.fir.analysis.js.checkers
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.*
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.directOverriddenFunctions
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.getAnnotationStringParameter
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.getContainingClassSymbol
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.hasAnnotationOrInsideAnnotatedClass
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.*
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isExpect
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isExternal
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isInterface
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.modality
|
||||
import org.jetbrains.kotlin.fir.isSubstitutionOrIntersectionOverride
|
||||
import org.jetbrains.kotlin.fir.resolve.providers.firProvider
|
||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.SymbolInternals
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||
import org.jetbrains.kotlin.js.PredefinedAnnotation
|
||||
import org.jetbrains.kotlin.js.common.isES5IdentifierPart
|
||||
import org.jetbrains.kotlin.js.common.isES5IdentifierStart
|
||||
import org.jetbrains.kotlin.name.JsStandardClassIds
|
||||
|
||||
private val FirBasedSymbol<*>.isExternal
|
||||
@@ -72,6 +72,13 @@ fun FirBasedSymbol<*>.getJsName(session: FirSession): String? {
|
||||
return getAnnotationStringParameter(JsStandardClassIds.Annotations.JsName, session)
|
||||
}
|
||||
|
||||
fun sanitizeName(name: String): String {
|
||||
if (name.isEmpty()) return "_"
|
||||
|
||||
val first = name.first().let { if (it.isES5IdentifierStart()) it else '_' }
|
||||
return first.toString() + name.drop(1).map { if (it.isES5IdentifierPart()) it else '_' }.joinToString("")
|
||||
}
|
||||
|
||||
fun FirBasedSymbol<*>.isNativeObject(session: FirSession): Boolean {
|
||||
if (hasAnnotationOrInsideAnnotatedClass(JsStandardClassIds.Annotations.JsNative, session) || isEffectivelyExternal(session)) {
|
||||
return true
|
||||
@@ -109,8 +116,35 @@ fun FirBasedSymbol<*>.isPredefinedObject(session: FirSession): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
fun FirBasedSymbol<*>.isExportedObject(session: FirSession): Boolean {
|
||||
val declaration = fir
|
||||
|
||||
if (declaration is FirMemberDeclaration) {
|
||||
val visibility = declaration.visibility
|
||||
if (visibility != Visibilities.Public && visibility != Visibilities.Protected) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return when {
|
||||
hasAnnotationOrInsideAnnotatedClass(JsStandardClassIds.Annotations.JsExportIgnore, session) -> false
|
||||
hasAnnotationOrInsideAnnotatedClass(JsStandardClassIds.Annotations.JsExport, session) -> true
|
||||
else -> getContainingFile(session)?.hasAnnotation(JsStandardClassIds.Annotations.JsExport, session) == true
|
||||
}
|
||||
}
|
||||
|
||||
private fun FirBasedSymbol<*>.getContainingFile(session: FirSession): FirFile? {
|
||||
return when (this) {
|
||||
is FirCallableSymbol<*> -> session.firProvider.getFirCallableContainerFile(this)
|
||||
is FirClassLikeSymbol<*> -> session.firProvider.getFirClassifierContainerFileIfAny(this)
|
||||
else -> return null
|
||||
}
|
||||
}
|
||||
|
||||
fun FirBasedSymbol<*>.isNativeObject(context: CheckerContext) = isNativeObject(context.session)
|
||||
|
||||
fun FirBasedSymbol<*>.isNativeInterface(context: CheckerContext) = isNativeInterface(context.session)
|
||||
|
||||
fun FirBasedSymbol<*>.isPredefinedObject(context: CheckerContext) = isPredefinedObject(context.session)
|
||||
|
||||
fun FirBasedSymbol<*>.isExportedObject(context: CheckerContext) = isExportedObject(context.session)
|
||||
|
||||
+1
@@ -28,6 +28,7 @@ object JsDeclarationCheckers : DeclarationCheckers() {
|
||||
FirJsExternalFileChecker,
|
||||
FirJsNameChecker,
|
||||
FirJsExportAnnotationChecker,
|
||||
FirJsExportDeclarationChecker,
|
||||
)
|
||||
|
||||
override val classCheckers: Set<FirClassChecker>
|
||||
|
||||
+224
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
* 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.KtFakeSourceElementKind
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirBasicDeclarationChecker
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.getAnnotationFirstArgument
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.isTopLevel
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.js.FirJsErrors
|
||||
import org.jetbrains.kotlin.fir.analysis.js.checkers.isEffectivelyExternal
|
||||
import org.jetbrains.kotlin.fir.analysis.js.checkers.isExportedObject
|
||||
import org.jetbrains.kotlin.fir.analysis.js.checkers.sanitizeName
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.*
|
||||
import org.jetbrains.kotlin.fir.expressions.FirConstExpression
|
||||
import org.jetbrains.kotlin.fir.symbols.SymbolInternals
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.js.common.RESERVED_KEYWORDS
|
||||
import org.jetbrains.kotlin.js.common.SPECIAL_KEYWORDS
|
||||
import org.jetbrains.kotlin.name.JsStandardClassIds
|
||||
|
||||
object FirJsExportDeclarationChecker : FirBasicDeclarationChecker() {
|
||||
override fun check(declaration: FirDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
if (!declaration.symbol.isExportedObject(context) || declaration !is FirMemberDeclaration) {
|
||||
return
|
||||
}
|
||||
|
||||
fun checkTypeParameter(typeParameter: FirTypeParameterRef) {
|
||||
for (upperBound in typeParameter.symbol.resolvedBounds) {
|
||||
if (!upperBound.type.isExportable(context.session)) {
|
||||
reporter.reportOn(typeParameter.source, FirJsErrors.NON_EXPORTABLE_TYPE, "upper bound", upperBound.type, context)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun checkValueParameter(valueParameter: FirValueParameter) {
|
||||
val type = valueParameter.returnTypeRef.coneType
|
||||
if (!type.isExportable(context.session)) {
|
||||
reporter.reportOn(valueParameter.source, FirJsErrors.NON_EXPORTABLE_TYPE, "parameter", type, context)
|
||||
}
|
||||
}
|
||||
|
||||
val hasJsName = declaration.hasAnnotation(JsStandardClassIds.Annotations.JsName, context.session)
|
||||
|
||||
fun reportWrongExportedDeclaration(kind: String) {
|
||||
reporter.reportOn(declaration.source, FirJsErrors.WRONG_EXPORTED_DECLARATION, kind, context)
|
||||
}
|
||||
|
||||
if (declaration.isExpect) {
|
||||
reportWrongExportedDeclaration("expect")
|
||||
}
|
||||
|
||||
validateDeclarationOnConsumableName(declaration, context, reporter)
|
||||
|
||||
when (declaration) {
|
||||
is FirFunction -> {
|
||||
for (typeParameter in declaration.typeParameters) {
|
||||
checkTypeParameter(typeParameter)
|
||||
}
|
||||
|
||||
if (declaration.isInlineWithReified) {
|
||||
reportWrongExportedDeclaration("inline function with reified type parameters")
|
||||
return
|
||||
}
|
||||
|
||||
if (declaration.isSuspend) {
|
||||
reportWrongExportedDeclaration("suspend function")
|
||||
return
|
||||
}
|
||||
|
||||
if (declaration is FirConstructor && !declaration.isPrimary && !hasJsName) {
|
||||
reportWrongExportedDeclaration("secondary constructor without @JsName")
|
||||
}
|
||||
|
||||
// Properties are checked instead of property accessors
|
||||
if (declaration is FirPropertyAccessor) {
|
||||
return
|
||||
}
|
||||
|
||||
for (parameter in declaration.valueParameters) {
|
||||
checkValueParameter(parameter)
|
||||
}
|
||||
|
||||
val returnType = declaration.returnTypeRef.coneType
|
||||
|
||||
if (!returnType.isExportable(context.session)) {
|
||||
reporter.reportOn(declaration.source, FirJsErrors.NON_EXPORTABLE_TYPE, "return type", returnType, context)
|
||||
}
|
||||
}
|
||||
|
||||
is FirProperty -> {
|
||||
if (declaration.source?.kind == KtFakeSourceElementKind.PropertyFromParameter) {
|
||||
return
|
||||
}
|
||||
|
||||
if (declaration.isExtension) {
|
||||
reportWrongExportedDeclaration("extension property")
|
||||
return
|
||||
}
|
||||
|
||||
val returnType = declaration.returnTypeRef.coneType
|
||||
|
||||
if (!returnType.isExportable(context.session)) {
|
||||
reporter.reportOn(declaration.source, FirJsErrors.NON_EXPORTABLE_TYPE, "return type", returnType, context)
|
||||
}
|
||||
}
|
||||
|
||||
is FirClass -> {
|
||||
for (typeParameter in declaration.typeParameters) {
|
||||
checkTypeParameter(typeParameter)
|
||||
}
|
||||
|
||||
val wrongDeclaration: String? = when (declaration.classKind) {
|
||||
ClassKind.ANNOTATION_CLASS -> "annotation class"
|
||||
ClassKind.CLASS -> when {
|
||||
context.isInsideInterface -> "nested class inside exported interface"
|
||||
declaration.isInline -> "value class"
|
||||
else -> null
|
||||
}
|
||||
else -> if (context.isInsideInterface) {
|
||||
"${if (declaration.status.isCompanion) "companion object" else "nested/inner declaration"} inside exported interface"
|
||||
} else null
|
||||
}
|
||||
|
||||
if (wrongDeclaration != null) {
|
||||
reportWrongExportedDeclaration(wrongDeclaration)
|
||||
}
|
||||
}
|
||||
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
|
||||
private val CheckerContext.isInsideInterface
|
||||
get(): Boolean {
|
||||
val parent = containingDeclarations.lastOrNull() as? FirClass
|
||||
return parent != null && parent.isInterface
|
||||
}
|
||||
|
||||
private val FirCallableDeclaration.isInlineWithReified: Boolean
|
||||
get() = when (this) {
|
||||
is FirPropertyAccessor -> {
|
||||
@OptIn(SymbolInternals::class)
|
||||
this.propertySymbol.fir.isInlineWithReified
|
||||
}
|
||||
else -> typeParameters.any { it.symbol.isReified }
|
||||
}
|
||||
|
||||
private fun ConeKotlinType.isExportableReturn(session: FirSession, currentlyProcessed: MutableSet<ConeKotlinType> = mutableSetOf()) =
|
||||
isUnit || isExportable(session, currentlyProcessed)
|
||||
|
||||
private fun ConeKotlinType.isExportable(
|
||||
session: FirSession,
|
||||
currentlyProcessed: MutableSet<ConeKotlinType> = mutableSetOf(),
|
||||
): Boolean {
|
||||
if (!currentlyProcessed.add(this)) {
|
||||
return true
|
||||
}
|
||||
|
||||
currentlyProcessed.add(this)
|
||||
val hasNonExportableArgument = typeArguments.any { it.type?.isExportable(session, currentlyProcessed) != true }
|
||||
|
||||
if (hasNonExportableArgument) {
|
||||
currentlyProcessed.remove(this)
|
||||
return false
|
||||
}
|
||||
|
||||
currentlyProcessed.remove(this)
|
||||
|
||||
if (isBasicFunctionType(session)) {
|
||||
typeArguments.lastOrNull()?.type?.isExportableReturn(session, currentlyProcessed)
|
||||
}
|
||||
|
||||
val nonNullable = withNullability(ConeNullability.NOT_NULL, session.typeContext)
|
||||
val isPrimitiveExportableType = nonNullable.isAny || nonNullable.isNullableAny
|
||||
|| nonNullable is ConeDynamicType || isPrimitiveExportableConeKotlinType
|
||||
val symbol = toSymbol(session)
|
||||
|
||||
return when {
|
||||
isPrimitiveExportableType -> true
|
||||
@OptIn(SymbolInternals::class)
|
||||
symbol?.fir is FirMemberDeclaration -> false
|
||||
isEnum -> true
|
||||
else -> symbol?.isEffectivelyExternal(session) == true || symbol?.isExportedObject(session) == true
|
||||
}
|
||||
}
|
||||
|
||||
private val ConeKotlinType.isPrimitiveExportableConeKotlinType: Boolean
|
||||
get() = this is ConeTypeParameterType
|
||||
|| isBoolean
|
||||
|| isThrowableOrNullableThrowable
|
||||
|| isString
|
||||
|| isPrimitiveNumberOrNullableType && !isLong
|
||||
|| isNothingOrNullableNothing
|
||||
|| isArrayType
|
||||
|
||||
private fun validateDeclarationOnConsumableName(
|
||||
declaration: FirMemberDeclaration,
|
||||
context: CheckerContext,
|
||||
reporter: DiagnosticReporter,
|
||||
) {
|
||||
if (!context.isTopLevel || declaration.nameOrSpecialName.isSpecial) {
|
||||
return
|
||||
}
|
||||
|
||||
val jsNameArgument = declaration.symbol.getAnnotationFirstArgument(JsStandardClassIds.Annotations.JsName, context.session)
|
||||
val reportTarget = jsNameArgument?.source ?: declaration.source
|
||||
val name = (jsNameArgument as? FirConstExpression<*>)?.value as? String ?: declaration.nameOrSpecialName.asString()
|
||||
|
||||
if (name in SPECIAL_KEYWORDS || (name !in RESERVED_KEYWORDS && sanitizeName(name) == name)) {
|
||||
return
|
||||
}
|
||||
|
||||
reporter.reportOn(reportTarget, FirJsErrors.NON_CONSUMABLE_EXPORTED_IDENTIFIER, name, context)
|
||||
}
|
||||
}
|
||||
@@ -736,9 +736,13 @@ fun FirBasedSymbol<*>.hasAnnotationOrInsideAnnotatedClass(classId: ClassId, sess
|
||||
fun FirDeclaration.hasAnnotationOrInsideAnnotatedClass(classId: ClassId, session: FirSession) =
|
||||
symbol.hasAnnotationOrInsideAnnotatedClass(classId, session)
|
||||
|
||||
fun FirBasedSymbol<*>.getAnnotationStringParameter(classId: ClassId, session: FirSession): String? {
|
||||
fun FirBasedSymbol<*>.getAnnotationFirstArgument(classId: ClassId, session: FirSession): FirExpression? {
|
||||
val annotation = getAnnotationByClassId(classId, session) as? FirAnnotationCall
|
||||
val expression = annotation?.argumentMapping?.mapping?.values?.firstOrNull() as? FirConstExpression<*>
|
||||
return annotation?.argumentMapping?.mapping?.values?.firstOrNull()
|
||||
}
|
||||
|
||||
fun FirBasedSymbol<*>.getAnnotationStringParameter(classId: ClassId, session: FirSession): String? {
|
||||
val expression = getAnnotationFirstArgument(classId, session) as? FirConstExpression<*>
|
||||
return expression?.value as? String
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,10 @@ val ConeKotlinType.isBoolean: Boolean get() = isBuiltinType(StandardClassIds.Boo
|
||||
val ConeKotlinType.isNullableBoolean: Boolean get() = isBuiltinType(StandardClassIds.Boolean, true)
|
||||
val ConeKotlinType.isBooleanOrNullableBoolean: Boolean get() = isBuiltinType(StandardClassIds.Boolean, null)
|
||||
|
||||
val ConeKotlinType.isThrowableOrNullableThrowable: Boolean get() = isAnyOfBuiltinType(setOf(StandardClassIds.Throwable))
|
||||
|
||||
val ConeKotlinType.isChar: Boolean get() = isBuiltinType(StandardClassIds.Char, false)
|
||||
val ConeKotlinType.isCharOrNullableChar: Boolean get() = isAnyOfBuiltinType(setOf(StandardClassIds.Char))
|
||||
val ConeKotlinType.isString: Boolean get() = isBuiltinType(StandardClassIds.String, false)
|
||||
|
||||
val ConeKotlinType.isEnum: Boolean get() = isBuiltinType(StandardClassIds.Enum, false)
|
||||
@@ -37,6 +40,8 @@ val ConeKotlinType.isUInt: Boolean get() = isBuiltinType(StandardClassIds.UInt,
|
||||
val ConeKotlinType.isULong: Boolean get() = isBuiltinType(StandardClassIds.ULong, false)
|
||||
val ConeKotlinType.isPrimitiveOrNullablePrimitive: Boolean get() = isAnyOfBuiltinType(StandardClassIds.primitiveTypes)
|
||||
val ConeKotlinType.isPrimitive: Boolean get() = isPrimitiveOrNullablePrimitive && nullability == ConeNullability.NOT_NULL
|
||||
val ConeKotlinType.isPrimitiveNumberOrNullableType: Boolean
|
||||
get() = isPrimitiveOrNullablePrimitive && !isBooleanOrNullableBoolean && !isCharOrNullableChar
|
||||
val ConeKotlinType.isArrayType: Boolean
|
||||
get() {
|
||||
return isBuiltinType(StandardClassIds.Array, false) ||
|
||||
|
||||
@@ -540,15 +540,6 @@ fun FirBasedSymbol<*>.getOwnerLookupTag(): ConeClassLikeLookupTag? {
|
||||
}
|
||||
}
|
||||
|
||||
fun FirClassLikeSymbol<*>.getContainingClassLookupTag(): ConeClassLikeLookupTag? {
|
||||
return if (classId.isLocal) {
|
||||
(fir as? FirRegularClass)?.containingClassForLocal()
|
||||
} else {
|
||||
val ownerId = classId.outerClassId
|
||||
ownerId?.let { it.toLookupTag() }
|
||||
}
|
||||
}
|
||||
|
||||
fun FirBasedSymbol<*>.isVariableOrNamedFunction(): Boolean {
|
||||
return this is FirVariableSymbol || this is FirNamedFunctionSymbol || this is FirPropertyAccessorSymbol
|
||||
}
|
||||
|
||||
+4
-1
@@ -233,7 +233,10 @@ abstract class BaseFirBuilder<T>(val baseSession: FirSession, val context: Conte
|
||||
fun constructorTypeParametersFromConstructedClass(ownerTypeParameters: List<FirTypeParameterRef>): List<FirTypeParameterRef> {
|
||||
return ownerTypeParameters.mapNotNull {
|
||||
val declaredTypeParameter = (it as? FirTypeParameter) ?: return@mapNotNull null
|
||||
buildConstructedClassTypeParameterRef { symbol = declaredTypeParameter.symbol }
|
||||
buildConstructedClassTypeParameterRef {
|
||||
source = declaredTypeParameter.symbol.source?.fakeElement(KtFakeSourceElementKind.ConstructorTypeParameter)
|
||||
symbol = declaredTypeParameter.symbol
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.fir.PrivateForInline
|
||||
import org.jetbrains.kotlin.fir.declarations.FirTypeParameterRef
|
||||
import org.jetbrains.kotlin.fir.declarations.builder.buildOuterClassTypeParameterRef
|
||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirFileSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
|
||||
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
@@ -48,6 +49,7 @@ class Context<T> {
|
||||
var forcedElementSourceKind: KtSourceElementKind? = null
|
||||
val dispatchReceiverTypesStack = mutableListOf<ConeClassLikeType>()
|
||||
var containerIsExpect: Boolean = false
|
||||
var containingFileSymbol: FirFileSymbol? = null
|
||||
|
||||
fun pushFirTypeParameters(isInnerOrLocal: Boolean, parameters: List<FirTypeParameterRef>) {
|
||||
capturedTypeParameters.add(StatusFirTypeParameterSymbolList(isInnerOrLocal, parameters.map { it.symbol }))
|
||||
|
||||
@@ -10,9 +10,11 @@ import org.jetbrains.kotlin.fir.declarations.utils.isLocal
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isSynthetic
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
|
||||
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
|
||||
import org.jetbrains.kotlin.fir.types.ConeIntersectionType
|
||||
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||
import org.jetbrains.kotlin.fir.types.toLookupTag
|
||||
|
||||
fun FirCallableSymbol<*>.dispatchReceiverClassTypeOrNull(): ConeClassLikeType? =
|
||||
fir.dispatchReceiverClassTypeOrNull()
|
||||
@@ -41,6 +43,15 @@ fun FirRegularClass.containingClassForLocal(): ConeClassLikeLookupTag? =
|
||||
fun FirDanglingModifierList.containingClass(): ConeClassLikeLookupTag? =
|
||||
containingClassAttr
|
||||
|
||||
fun FirClassLikeSymbol<*>.getContainingClassLookupTag(): ConeClassLikeLookupTag? {
|
||||
return if (classId.isLocal) {
|
||||
(fir as? FirRegularClass)?.containingClassForLocal()
|
||||
} else {
|
||||
val ownerId = classId.outerClassId
|
||||
ownerId?.toLookupTag()
|
||||
}
|
||||
}
|
||||
|
||||
private object ContainingClassKey : FirDeclarationDataKey()
|
||||
var FirCallableDeclaration.containingClassForStaticMemberAttr: ConeClassLikeLookupTag? by FirDeclarationDataRegistry.data(ContainingClassKey)
|
||||
var FirRegularClass.containingClassForLocalAttr: ConeClassLikeLookupTag? by FirDeclarationDataRegistry.data(ContainingClassKey)
|
||||
|
||||
+2
-12
@@ -7,9 +7,9 @@ package org.jetbrains.kotlin.fir.declarations.comparators
|
||||
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.classId
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.nameOrSpecialName
|
||||
import org.jetbrains.kotlin.fir.render
|
||||
import org.jetbrains.kotlin.fir.types.FirTypeRefComparator
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
object FirMemberDeclarationComparator : Comparator<FirMemberDeclaration> {
|
||||
// Comparing different kinds of callable members by assigning distinct priorities to those members.
|
||||
@@ -28,16 +28,6 @@ object FirMemberDeclarationComparator : Comparator<FirMemberDeclaration> {
|
||||
is FirBackingField -> 0
|
||||
}
|
||||
|
||||
private val FirMemberDeclaration.name: Name
|
||||
get() = when (this) {
|
||||
is FirCallableDeclaration ->
|
||||
this.symbol.callableId.callableName
|
||||
is FirClass ->
|
||||
this.classId.shortClassName
|
||||
is FirTypeAlias ->
|
||||
this.name
|
||||
}
|
||||
|
||||
override fun compare(a: FirMemberDeclaration, b: FirMemberDeclaration): Int {
|
||||
val priorityDiff = a.priority - b.priority
|
||||
if (priorityDiff != 0) {
|
||||
@@ -51,7 +41,7 @@ object FirMemberDeclarationComparator : Comparator<FirMemberDeclaration> {
|
||||
return 0
|
||||
}
|
||||
|
||||
return a.name.compareTo(b.name)
|
||||
return a.nameOrSpecialName.compareTo(b.nameOrSpecialName)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+11
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
|
||||
import org.jetbrains.kotlin.fir.types.coneTypeSafe
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
val FirTypeAlias.expandedConeType: ConeClassLikeType? get() = expandedTypeRef.coneTypeSafe()
|
||||
|
||||
@@ -45,3 +46,13 @@ val FirDeclaration.isNonLocal
|
||||
}
|
||||
|
||||
val FirCallableDeclaration.isExtension get() = receiverParameter != null
|
||||
|
||||
val FirMemberDeclaration.nameOrSpecialName: Name
|
||||
get() = when (this) {
|
||||
is FirCallableDeclaration ->
|
||||
this.symbol.callableId.callableName
|
||||
is FirClass ->
|
||||
this.classId.shortClassName
|
||||
is FirTypeAlias ->
|
||||
this.name
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user