[FIR] Implement extension for providing additional type attributes
This commit is contained in:
committed by
TeamCityServer
parent
32709151c3
commit
38877ba842
@@ -89,6 +89,11 @@ object CompilerConeAttributes {
|
|||||||
UnsafeVariance.ANNOTATION_CLASS_ID to UnsafeVariance
|
UnsafeVariance.ANNOTATION_CLASS_ID to UnsafeVariance
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val classIdByCompilerAttribute: Map<ConeAttribute<*>, ClassId> = compilerAttributeByClassId.entries.associateBy(
|
||||||
|
keySelector = { it.value },
|
||||||
|
valueTransform = { it.key }
|
||||||
|
)
|
||||||
|
|
||||||
val compilerAttributeByFqName: Map<FqName, ConeAttribute<*>> = compilerAttributeByClassId.mapKeys { it.key.asSingleFqName() }
|
val compilerAttributeByFqName: Map<FqName, ConeAttribute<*>> = compilerAttributeByClassId.mapKeys { it.key.asSingleFqName() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ abstract class ConeAttribute<T : ConeAttribute<T>> : AnnotationMarker {
|
|||||||
*
|
*
|
||||||
* This function must be symmetrical: a.add(b) == b.add(a)
|
* This function must be symmetrical: a.add(b) == b.add(a)
|
||||||
*/
|
*/
|
||||||
abstract fun add(other: @UnsafeVariance T?): T
|
abstract fun add(other: @UnsafeVariance T?): T?
|
||||||
abstract fun isSubtypeOf(other: @UnsafeVariance T?): Boolean
|
abstract fun isSubtypeOf(other: @UnsafeVariance T?): Boolean
|
||||||
|
|
||||||
abstract override fun toString(): String
|
abstract override fun toString(): String
|
||||||
|
|||||||
+1
-1
@@ -609,7 +609,7 @@ class FirMemberDeserializer(private val c: FirDeserializationContext) {
|
|||||||
private fun ProtoBuf.Type.toTypeRef(context: FirDeserializationContext): FirTypeRef {
|
private fun ProtoBuf.Type.toTypeRef(context: FirDeserializationContext): FirTypeRef {
|
||||||
return buildResolvedTypeRef {
|
return buildResolvedTypeRef {
|
||||||
annotations += context.annotationDeserializer.loadTypeAnnotations(this@toTypeRef, context.nameResolver)
|
annotations += context.annotationDeserializer.loadTypeAnnotations(this@toTypeRef, context.nameResolver)
|
||||||
val attributes = annotations.computeTypeAttributes()
|
val attributes = annotations.computeTypeAttributes(context.session)
|
||||||
type = context.typeDeserializer.type(this@toTypeRef, attributes)
|
type = context.typeDeserializer.type(this@toTypeRef, attributes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -109,7 +109,7 @@ class FirTypeDeserializer(
|
|||||||
|
|
||||||
fun type(proto: ProtoBuf.Type): ConeKotlinType {
|
fun type(proto: ProtoBuf.Type): ConeKotlinType {
|
||||||
val annotations = annotationDeserializer.loadTypeAnnotations(proto, nameResolver)
|
val annotations = annotationDeserializer.loadTypeAnnotations(proto, nameResolver)
|
||||||
val attributes = annotations.computeTypeAttributes()
|
val attributes = annotations.computeTypeAttributes(moduleData.session)
|
||||||
return type(proto, attributes)
|
return type(proto, attributes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+39
-3
@@ -23,6 +23,8 @@ import org.jetbrains.kotlin.fir.expressions.FirExpression
|
|||||||
import org.jetbrains.kotlin.fir.expressions.FirNamedArgumentExpression
|
import org.jetbrains.kotlin.fir.expressions.FirNamedArgumentExpression
|
||||||
import org.jetbrains.kotlin.fir.expressions.builder.buildAnnotation
|
import org.jetbrains.kotlin.fir.expressions.builder.buildAnnotation
|
||||||
import org.jetbrains.kotlin.fir.expressions.impl.FirEmptyAnnotationArgumentMapping
|
import org.jetbrains.kotlin.fir.expressions.impl.FirEmptyAnnotationArgumentMapping
|
||||||
|
import org.jetbrains.kotlin.fir.extensions.extensionService
|
||||||
|
import org.jetbrains.kotlin.fir.extensions.typeAttributeExtensions
|
||||||
import org.jetbrains.kotlin.fir.resolve.*
|
import org.jetbrains.kotlin.fir.resolve.*
|
||||||
import org.jetbrains.kotlin.fir.resolve.calls.varargElementType
|
import org.jetbrains.kotlin.fir.resolve.calls.varargElementType
|
||||||
import org.jetbrains.kotlin.fir.resolve.inference.isSuspendFunctionType
|
import org.jetbrains.kotlin.fir.resolve.inference.isSuspendFunctionType
|
||||||
@@ -34,9 +36,11 @@ import org.jetbrains.kotlin.fir.serialization.constant.EnumValue
|
|||||||
import org.jetbrains.kotlin.fir.serialization.constant.IntValue
|
import org.jetbrains.kotlin.fir.serialization.constant.IntValue
|
||||||
import org.jetbrains.kotlin.fir.serialization.constant.StringValue
|
import org.jetbrains.kotlin.fir.serialization.constant.StringValue
|
||||||
import org.jetbrains.kotlin.fir.serialization.constant.toConstantValue
|
import org.jetbrains.kotlin.fir.serialization.constant.toConstantValue
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLikeLookupTagImpl
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
||||||
import org.jetbrains.kotlin.fir.types.*
|
import org.jetbrains.kotlin.fir.types.*
|
||||||
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
|
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
|
||||||
|
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
|
||||||
import org.jetbrains.kotlin.fir.types.impl.FirImplicitNullableAnyTypeRef
|
import org.jetbrains.kotlin.fir.types.impl.FirImplicitNullableAnyTypeRef
|
||||||
import org.jetbrains.kotlin.metadata.ProtoBuf
|
import org.jetbrains.kotlin.metadata.ProtoBuf
|
||||||
import org.jetbrains.kotlin.metadata.deserialization.Flags
|
import org.jetbrains.kotlin.metadata.deserialization.Flags
|
||||||
@@ -606,9 +610,41 @@ class FirElementSerializer private constructor(
|
|||||||
fun typeId(type: ConeKotlinType): Int = typeTable[typeProto(type)]
|
fun typeId(type: ConeKotlinType): Int = typeTable[typeProto(type)]
|
||||||
|
|
||||||
private fun typeProto(typeRef: FirTypeRef, toSuper: Boolean = false): ProtoBuf.Type.Builder {
|
private fun typeProto(typeRef: FirTypeRef, toSuper: Boolean = false): ProtoBuf.Type.Builder {
|
||||||
return typeProto(typeRef.coneType, toSuper, correspondingTypeRef = typeRef).also {
|
val coneType = typeRef.coneType
|
||||||
for (annotation in typeRef.annotations) {
|
return typeProto(coneType, toSuper, correspondingTypeRef = typeRef).also { typeProto ->
|
||||||
extension.serializeTypeAnnotation(annotation, it)
|
for (annotation in coneType.attributes.customAnnotations) {
|
||||||
|
extension.serializeTypeAnnotation(annotation, typeProto)
|
||||||
|
}
|
||||||
|
|
||||||
|
val compilerAttributes = mutableListOf<ConeAttribute<*>>()
|
||||||
|
val extensionAttributes = mutableListOf<ConeAttribute<*>>()
|
||||||
|
for (attribute in coneType.attributes) {
|
||||||
|
when (attribute) {
|
||||||
|
is CustomAnnotationTypeAttribute -> continue
|
||||||
|
in CompilerConeAttributes.classIdByCompilerAttribute -> compilerAttributes += attribute
|
||||||
|
else -> extensionAttributes += attribute
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (attribute in compilerAttributes) {
|
||||||
|
val annotation = buildAnnotation {
|
||||||
|
annotationTypeRef = buildResolvedTypeRef {
|
||||||
|
type = ConeClassLikeTypeImpl(
|
||||||
|
ConeClassLikeLookupTagImpl(CompilerConeAttributes.classIdByCompilerAttribute.getValue(attribute)),
|
||||||
|
emptyArray(),
|
||||||
|
isNullable = false
|
||||||
|
)
|
||||||
|
}
|
||||||
|
argumentMapping = FirEmptyAnnotationArgumentMapping
|
||||||
|
}
|
||||||
|
extension.serializeTypeAnnotation(annotation, typeProto)
|
||||||
|
}
|
||||||
|
|
||||||
|
for (attributeExtension in session.extensionService.typeAttributeExtensions) {
|
||||||
|
for (attribute in extensionAttributes) {
|
||||||
|
val annotation = attributeExtension.convertAttributeToAnnotation(attribute) ?: continue
|
||||||
|
extension.serializeTypeAnnotation(annotation, typeProto)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-1
@@ -15,7 +15,8 @@ abstract class FirExtensionRegistrar {
|
|||||||
FirStatusTransformerExtension::class,
|
FirStatusTransformerExtension::class,
|
||||||
FirDeclarationGenerationExtension::class,
|
FirDeclarationGenerationExtension::class,
|
||||||
AbstractFirAdditionalCheckersExtension::class,
|
AbstractFirAdditionalCheckersExtension::class,
|
||||||
FirSupertypeGenerationExtension::class
|
FirSupertypeGenerationExtension::class,
|
||||||
|
FirTypeAttributeExtension::class,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,6 +45,11 @@ abstract class FirExtensionRegistrar {
|
|||||||
operator fun ((FirSession) -> FirSupertypeGenerationExtension).unaryPlus() {
|
operator fun ((FirSession) -> FirSupertypeGenerationExtension).unaryPlus() {
|
||||||
registerExtension(FirSupertypeGenerationExtension::class, FirSupertypeGenerationExtension.Factory { this.invoke(it) })
|
registerExtension(FirSupertypeGenerationExtension::class, FirSupertypeGenerationExtension.Factory { this.invoke(it) })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JvmName("plusTypeAttributeExtension")
|
||||||
|
operator fun ((FirSession) -> FirTypeAttributeExtension).unaryPlus() {
|
||||||
|
registerExtension(FirTypeAttributeExtension::class, FirTypeAttributeExtension.Factory { this.invoke(it) })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(PluginServicesInitialization::class)
|
@OptIn(PluginServicesInitialization::class)
|
||||||
|
|||||||
+10
-7
@@ -243,13 +243,16 @@ class FirTypeResolverImpl(private val session: FirSession) : FirTypeResolver() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return symbol.constructType(allTypeArguments.toTypedArray(), typeRef.isMarkedNullable, typeRef.annotations.computeTypeAttributes())
|
return symbol.constructType(
|
||||||
.also {
|
allTypeArguments.toTypedArray(),
|
||||||
val lookupTag = it.lookupTag
|
typeRef.isMarkedNullable,
|
||||||
if (lookupTag is ConeClassLikeLookupTagImpl && symbol is FirClassLikeSymbol<*>) {
|
typeRef.annotations.computeTypeAttributes(session)
|
||||||
lookupTag.bindSymbolToLookupTag(session, symbol)
|
).also {
|
||||||
}
|
val lookupTag = it.lookupTag
|
||||||
|
if (lookupTag is ConeClassLikeLookupTagImpl && symbol is FirClassLikeSymbol<*>) {
|
||||||
|
lookupTag.bindSymbolToLookupTag(session, symbol)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(SymbolInternals::class)
|
@OptIn(SymbolInternals::class)
|
||||||
@@ -352,7 +355,7 @@ class FirTypeResolverImpl(private val session: FirSession) : FirTypeResolver() {
|
|||||||
} else {
|
} else {
|
||||||
StandardClassIds.FunctionN(typeRef.parametersCount)
|
StandardClassIds.FunctionN(typeRef.parametersCount)
|
||||||
}
|
}
|
||||||
val attributes = typeRef.annotations.computeTypeAttributes()
|
val attributes = typeRef.annotations.computeTypeAttributes(session)
|
||||||
val symbol = resolveBuiltInQualified(classId, session)
|
val symbol = resolveBuiltInQualified(classId, session)
|
||||||
return ConeClassLikeTypeImpl(
|
return ConeClassLikeTypeImpl(
|
||||||
symbol.toLookupTag().also {
|
symbol.toLookupTag().also {
|
||||||
|
|||||||
+42
@@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 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.extensions
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
|
||||||
|
import org.jetbrains.kotlin.fir.types.ConeAttribute
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Note that when you declare your own attribute you HAVE TO declare accessor to it using following syntax:
|
||||||
|
*
|
||||||
|
* class MyAttribute : ConeAttribute<MyAttribute>() {...}
|
||||||
|
*
|
||||||
|
* val ConeAttributes.myAttribute: MyAttribute? by ConeAttributes.attributeAccessor<MyAttribute>()
|
||||||
|
*/
|
||||||
|
abstract class FirTypeAttributeExtension(session: FirSession) : FirExtension(session) {
|
||||||
|
companion object {
|
||||||
|
val NAME = FirExtensionPointName("AdditionalTypeAttributeExtension")
|
||||||
|
}
|
||||||
|
|
||||||
|
final override val name: FirExtensionPointName
|
||||||
|
get() = NAME
|
||||||
|
|
||||||
|
final override val extensionType: KClass<out FirExtension>
|
||||||
|
get() = FirTypeAttributeExtension::class
|
||||||
|
|
||||||
|
abstract fun extractAttributeFromAnnotation(annotation: FirAnnotation): ConeAttribute<*>?
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Please don't convert attributes which you didn't create
|
||||||
|
* If [attribute] came from compiler or another plugin just return null
|
||||||
|
*/
|
||||||
|
abstract fun convertAttributeToAnnotation(attribute: ConeAttribute<*>): FirAnnotation?
|
||||||
|
|
||||||
|
fun interface Factory : FirExtension.Factory<FirTypeAttributeExtension>
|
||||||
|
}
|
||||||
|
|
||||||
|
val FirExtensionService.typeAttributeExtensions: List<FirTypeAttributeExtension> by FirExtensionService.registeredExtensions()
|
||||||
@@ -6,10 +6,13 @@
|
|||||||
package org.jetbrains.kotlin.fir.types
|
package org.jetbrains.kotlin.fir.types
|
||||||
|
|
||||||
import org.jetbrains.kotlin.builtins.functions.FunctionClassKind
|
import org.jetbrains.kotlin.builtins.functions.FunctionClassKind
|
||||||
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
|
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirConstExpression
|
import org.jetbrains.kotlin.fir.expressions.FirConstExpression
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirExpressionWithSmartcast
|
import org.jetbrains.kotlin.fir.expressions.FirExpressionWithSmartcast
|
||||||
|
import org.jetbrains.kotlin.fir.extensions.extensionService
|
||||||
|
import org.jetbrains.kotlin.fir.extensions.typeAttributeExtensions
|
||||||
import org.jetbrains.kotlin.fir.render
|
import org.jetbrains.kotlin.fir.render
|
||||||
import org.jetbrains.kotlin.fir.types.impl.FirImplicitBuiltinTypeRef
|
import org.jetbrains.kotlin.fir.types.impl.FirImplicitBuiltinTypeRef
|
||||||
import org.jetbrains.kotlin.name.ClassId
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
@@ -109,26 +112,25 @@ fun ConeClassLikeType.toConstKind(): ConstantValueKind<*>? = when (lookupTag.cla
|
|||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
|
|
||||||
fun List<FirAnnotation>.computeTypeAttributes(
|
fun List<FirAnnotation>.computeTypeAttributes(session: FirSession): ConeAttributes {
|
||||||
additionalProcessor: MutableList<ConeAttribute<*>>.(ClassId) -> Unit = {}
|
|
||||||
): ConeAttributes {
|
|
||||||
if (this.isEmpty()) return ConeAttributes.Empty
|
if (this.isEmpty()) return ConeAttributes.Empty
|
||||||
val attributes = mutableListOf<ConeAttribute<*>>()
|
val attributes = mutableListOf<ConeAttribute<*>>()
|
||||||
val customAnnotations = mutableListOf<FirAnnotation>()
|
val customAnnotations = mutableListOf<FirAnnotation>()
|
||||||
for (annotation in this) {
|
for (annotation in this) {
|
||||||
val type = annotation.annotationTypeRef.coneTypeSafe<ConeClassLikeType>() ?: continue
|
val type = annotation.annotationTypeRef.coneTypeSafe<ConeClassLikeType>() ?: continue
|
||||||
when (val classId = type.lookupTag.classId) {
|
when (type.lookupTag.classId) {
|
||||||
CompilerConeAttributes.Exact.ANNOTATION_CLASS_ID -> attributes += CompilerConeAttributes.Exact
|
CompilerConeAttributes.Exact.ANNOTATION_CLASS_ID -> attributes += CompilerConeAttributes.Exact
|
||||||
CompilerConeAttributes.NoInfer.ANNOTATION_CLASS_ID -> attributes += CompilerConeAttributes.NoInfer
|
CompilerConeAttributes.NoInfer.ANNOTATION_CLASS_ID -> attributes += CompilerConeAttributes.NoInfer
|
||||||
CompilerConeAttributes.ExtensionFunctionType.ANNOTATION_CLASS_ID -> attributes += CompilerConeAttributes.ExtensionFunctionType
|
CompilerConeAttributes.ExtensionFunctionType.ANNOTATION_CLASS_ID -> attributes += CompilerConeAttributes.ExtensionFunctionType
|
||||||
CompilerConeAttributes.UnsafeVariance.ANNOTATION_CLASS_ID -> attributes += CompilerConeAttributes.UnsafeVariance
|
CompilerConeAttributes.UnsafeVariance.ANNOTATION_CLASS_ID -> attributes += CompilerConeAttributes.UnsafeVariance
|
||||||
else -> {
|
else -> {
|
||||||
val annotationAttributes = mutableListOf<ConeAttribute<*>>()
|
val attributeFromPlugin = session.extensionService.typeAttributeExtensions.firstNotNullOfOrNull {
|
||||||
additionalProcessor.invoke(annotationAttributes, classId)
|
it.extractAttributeFromAnnotation(annotation)
|
||||||
if (annotationAttributes.isEmpty()) {
|
}
|
||||||
customAnnotations += annotation
|
if (attributeFromPlugin != null) {
|
||||||
|
attributes += attributeFromPlugin
|
||||||
} else {
|
} else {
|
||||||
attributes += annotationAttributes
|
customAnnotations += annotation
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-1
@@ -20,6 +20,12 @@ annotation class G
|
|||||||
|
|
||||||
annotation class AllPublic(val visibility: Visibility)
|
annotation class AllPublic(val visibility: Visibility)
|
||||||
|
|
||||||
|
@Target(AnnotationTarget.TYPE)
|
||||||
|
annotation class Positive
|
||||||
|
|
||||||
|
@Target(AnnotationTarget.TYPE)
|
||||||
|
annotation class Negative
|
||||||
|
|
||||||
enum class Visibility {
|
enum class Visibility {
|
||||||
Public, Internal, Private, Protected
|
Public, Internal, Private, Protected
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-1
@@ -8,16 +8,24 @@ package org.jetbrains.kotlin.fir.plugin
|
|||||||
import org.jetbrains.kotlin.fir.FirSession
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.DeclarationCheckers
|
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.DeclarationCheckers
|
||||||
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirSimpleFunctionChecker
|
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirSimpleFunctionChecker
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.checkers.expression.ExpressionCheckers
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirFunctionCallChecker
|
||||||
import org.jetbrains.kotlin.fir.analysis.extensions.FirAdditionalCheckersExtension
|
import org.jetbrains.kotlin.fir.analysis.extensions.FirAdditionalCheckersExtension
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirPluginKey
|
import org.jetbrains.kotlin.fir.declarations.FirPluginKey
|
||||||
import org.jetbrains.kotlin.fir.plugin.checkers.DummyNameChecker
|
import org.jetbrains.kotlin.fir.plugin.checkers.DummyNameChecker
|
||||||
|
import org.jetbrains.kotlin.fir.plugin.checkers.SignedNumberCallChecker
|
||||||
|
|
||||||
class AllOpenAdditionalCheckers(session: FirSession) : FirAdditionalCheckersExtension(session) {
|
class AllOpenAdditionalCheckers(session: FirSession) : FirAdditionalCheckersExtension(session) {
|
||||||
override val key: FirPluginKey
|
override val key: FirPluginKey
|
||||||
get() = AllOpenPluginKey
|
get() = AllOpenPluginKey
|
||||||
|
|
||||||
override val declarationCheckers: DeclarationCheckers = object : DeclarationCheckers() {
|
override val declarationCheckers: DeclarationCheckers = object : DeclarationCheckers() {
|
||||||
override val simpleFunctionCheckers: Set<FirSimpleFunctionChecker>
|
override val simpleFunctionCheckers: Set<FirSimpleFunctionChecker>
|
||||||
get() = setOf(DummyNameChecker)
|
get() = setOf(DummyNameChecker)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override val expressionCheckers: ExpressionCheckers = object : ExpressionCheckers() {
|
||||||
|
override val functionCallCheckers: Set<FirFunctionCallChecker>
|
||||||
|
get() = setOf(SignedNumberCallChecker)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.fir.plugin
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrar
|
import org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrar
|
||||||
import org.jetbrains.kotlin.fir.plugin.generators.*
|
import org.jetbrains.kotlin.fir.plugin.generators.*
|
||||||
|
import org.jetbrains.kotlin.fir.plugin.types.FirNumberSignAttributeExtension
|
||||||
|
|
||||||
class FirAllOpenComponentRegistrar : FirExtensionRegistrar() {
|
class FirAllOpenComponentRegistrar : FirExtensionRegistrar() {
|
||||||
override fun ExtensionRegistrarContext.configurePlugin() {
|
override fun ExtensionRegistrarContext.configurePlugin() {
|
||||||
@@ -14,6 +15,7 @@ class FirAllOpenComponentRegistrar : FirExtensionRegistrar() {
|
|||||||
+::AllOpenVisibilityTransformer
|
+::AllOpenVisibilityTransformer
|
||||||
+::AllOpenSupertypeGenerator
|
+::AllOpenSupertypeGenerator
|
||||||
+::AllOpenAdditionalCheckers
|
+::AllOpenAdditionalCheckers
|
||||||
|
+::FirNumberSignAttributeExtension
|
||||||
|
|
||||||
// Declaration generators
|
// Declaration generators
|
||||||
+::AllOpenTopLevelDeclarationsGenerator
|
+::AllOpenTopLevelDeclarationsGenerator
|
||||||
|
|||||||
+2
@@ -7,8 +7,10 @@ package org.jetbrains.kotlin.fir.plugin.checkers
|
|||||||
|
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.SourceElementPositioningStrategies
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.SourceElementPositioningStrategies
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.error2
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.warning1
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.warning1
|
||||||
|
|
||||||
object AllOpenErrors {
|
object AllOpenErrors {
|
||||||
val FUNCTION_WITH_DUMMY_NAME by warning1<PsiElement, String>(SourceElementPositioningStrategies.DECLARATION_NAME)
|
val FUNCTION_WITH_DUMMY_NAME by warning1<PsiElement, String>(SourceElementPositioningStrategies.DECLARATION_NAME)
|
||||||
|
val ILLEGAL_NUMBER_SIGN by error2<PsiElement, String, String>()
|
||||||
}
|
}
|
||||||
|
|||||||
+39
@@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 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.plugin.checkers
|
||||||
|
|
||||||
|
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.DiagnosticReporter
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.InternalDiagnosticFactoryMethod
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.withSuppressedDiagnostics
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.argumentMapping
|
||||||
|
import org.jetbrains.kotlin.fir.plugin.types.ConeNumberSignAttribute
|
||||||
|
import org.jetbrains.kotlin.fir.plugin.types.numberSign
|
||||||
|
import org.jetbrains.kotlin.fir.types.coneType
|
||||||
|
|
||||||
|
object SignedNumberCallChecker : FirFunctionCallChecker() {
|
||||||
|
@OptIn(InternalDiagnosticFactoryMethod::class)
|
||||||
|
override fun check(expression: FirFunctionCall, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||||
|
val argumentMapping = expression.argumentMapping ?: return
|
||||||
|
for ((argument, parameter) in argumentMapping.entries) {
|
||||||
|
val expectedSign = parameter.returnTypeRef.coneType.attributes.numberSign ?: continue
|
||||||
|
val actualSign = argument.typeRef.coneType.attributes.numberSign
|
||||||
|
if (expectedSign != actualSign) {
|
||||||
|
withSuppressedDiagnostics(argument, context) {
|
||||||
|
reporter.reportOn(argument.source, AllOpenErrors.ILLEGAL_NUMBER_SIGN, expectedSign.asString(), actualSign.asString(), it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun ConeNumberSignAttribute?.asString(): String = when (this?.sign) {
|
||||||
|
null -> "None"
|
||||||
|
else -> sign.name
|
||||||
|
}
|
||||||
|
}
|
||||||
+73
@@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 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.plugin.types
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.fir.types.ConeAttribute
|
||||||
|
import org.jetbrains.kotlin.fir.types.ConeAttributes
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
class ConeNumberSignAttribute private constructor(val sign: Sign) : ConeAttribute<ConeNumberSignAttribute>() {
|
||||||
|
companion object {
|
||||||
|
private val Positive = ConeNumberSignAttribute(Sign.Positive)
|
||||||
|
private val Negative = ConeNumberSignAttribute(Sign.Negative)
|
||||||
|
|
||||||
|
fun fromSign(sign: Sign?): ConeNumberSignAttribute? {
|
||||||
|
return when (sign) {
|
||||||
|
Sign.Positive -> Positive
|
||||||
|
Sign.Negative -> Negative
|
||||||
|
null -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class Sign {
|
||||||
|
Positive {
|
||||||
|
override fun combine(other: Sign?): Sign? = when (other) {
|
||||||
|
Positive -> Positive
|
||||||
|
Negative,
|
||||||
|
null -> null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Negative {
|
||||||
|
override fun combine(other: Sign?): Sign? = when (other) {
|
||||||
|
Negative -> Negative
|
||||||
|
Positive,
|
||||||
|
null -> null
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
abstract fun combine(other: Sign?): Sign?
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun combine(other: ConeNumberSignAttribute?): ConeNumberSignAttribute? {
|
||||||
|
return fromSign(sign.combine(other?.sign))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun union(other: ConeNumberSignAttribute?): ConeNumberSignAttribute? {
|
||||||
|
return combine(other)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun intersect(other: ConeNumberSignAttribute?): ConeNumberSignAttribute? {
|
||||||
|
return combine(other)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun add(other: ConeNumberSignAttribute?): ConeNumberSignAttribute? {
|
||||||
|
return combine(other)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isSubtypeOf(other: ConeNumberSignAttribute?): Boolean {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return "@${sign.name}"
|
||||||
|
}
|
||||||
|
|
||||||
|
override val key: KClass<out ConeNumberSignAttribute>
|
||||||
|
get() = ConeNumberSignAttribute::class
|
||||||
|
}
|
||||||
|
|
||||||
|
val ConeAttributes.numberSign: ConeNumberSignAttribute? by ConeAttributes.attributeAccessor<ConeNumberSignAttribute>()
|
||||||
+62
@@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 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.plugin.types
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.FirPluginKey
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.builder.buildAnnotation
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.impl.FirEmptyAnnotationArgumentMapping
|
||||||
|
import org.jetbrains.kotlin.fir.extensions.FirTypeAttributeExtension
|
||||||
|
import org.jetbrains.kotlin.fir.plugin.AllOpenPluginKey
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLikeLookupTagImpl
|
||||||
|
import org.jetbrains.kotlin.fir.types.ConeAttribute
|
||||||
|
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
|
||||||
|
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
|
||||||
|
import org.jetbrains.kotlin.fir.types.classId
|
||||||
|
import org.jetbrains.kotlin.fir.types.coneTypeSafe
|
||||||
|
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
|
||||||
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
|
||||||
|
class FirNumberSignAttributeExtension(session: FirSession) : FirTypeAttributeExtension(session) {
|
||||||
|
companion object {
|
||||||
|
private val PACKAGE_FQN = FqName("org.jetbrains.kotlin.fir.plugin")
|
||||||
|
private val PositiveClassId = ClassId(PACKAGE_FQN, Name.identifier("Positive"))
|
||||||
|
private val NegativeClassId = ClassId(PACKAGE_FQN, Name.identifier("Negative"))
|
||||||
|
}
|
||||||
|
|
||||||
|
override val key: FirPluginKey
|
||||||
|
get() = AllOpenPluginKey
|
||||||
|
|
||||||
|
override fun extractAttributeFromAnnotation(annotation: FirAnnotation): ConeAttribute<*>? {
|
||||||
|
val sign = when (annotation.annotationTypeRef.coneTypeSafe<ConeClassLikeType>()?.classId) {
|
||||||
|
PositiveClassId -> ConeNumberSignAttribute.Sign.Positive
|
||||||
|
NegativeClassId -> ConeNumberSignAttribute.Sign.Negative
|
||||||
|
else -> return null
|
||||||
|
}
|
||||||
|
return ConeNumberSignAttribute.fromSign(sign)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun convertAttributeToAnnotation(attribute: ConeAttribute<*>): FirAnnotation? {
|
||||||
|
if (attribute !is ConeNumberSignAttribute) return null
|
||||||
|
val classId = when (attribute.sign) {
|
||||||
|
ConeNumberSignAttribute.Sign.Positive -> PositiveClassId
|
||||||
|
ConeNumberSignAttribute.Sign.Negative -> NegativeClassId
|
||||||
|
}
|
||||||
|
return buildAnnotation {
|
||||||
|
annotationTypeRef = buildResolvedTypeRef {
|
||||||
|
type = ConeClassLikeTypeImpl(
|
||||||
|
ConeClassLikeLookupTagImpl(classId),
|
||||||
|
emptyArray(),
|
||||||
|
isNullable = false
|
||||||
|
)
|
||||||
|
}
|
||||||
|
argumentMapping = FirEmptyAnnotationArgumentMapping
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+26
@@ -0,0 +1,26 @@
|
|||||||
|
FILE: signedNumbersCheckers.kt
|
||||||
|
public final fun takePositive(x: R|@Positive kotlin/Number|): R|kotlin/Unit| {
|
||||||
|
}
|
||||||
|
public final fun takeNegative(x: R|@Negative kotlin/Number|): R|kotlin/Unit| {
|
||||||
|
}
|
||||||
|
public final fun takeAny(x: R|kotlin/Number|): R|kotlin/Unit| {
|
||||||
|
}
|
||||||
|
public final fun <K> id(x: R|K|): R|K| {
|
||||||
|
^id R|<local>/x|
|
||||||
|
}
|
||||||
|
public final fun <K> select(x: R|K|, y: R|K|): R|K| {
|
||||||
|
^select R|<local>/x|
|
||||||
|
}
|
||||||
|
public final fun test(positiveInt: R|@Positive kotlin/Int|, positiveDouble: R|@Positive kotlin/Double|, negativeDouble: R|@Negative kotlin/Double|): R|kotlin/Unit| {
|
||||||
|
R|/takePositive|(R|<local>/positiveInt|)
|
||||||
|
R|/takeNegative|(R|<local>/negativeDouble|)
|
||||||
|
R|/takeAny|(R|<local>/positiveInt|)
|
||||||
|
R|/takePositive|(R|<local>/negativeDouble|)
|
||||||
|
R|/takeNegative|(R|<local>/positiveInt|)
|
||||||
|
R|/takePositive|(R|/id|<R|@Positive kotlin/Int|>(R|<local>/positiveInt|))
|
||||||
|
R|/takeNegative|(R|/id|<R|@Positive kotlin/Int|>(R|<local>/positiveInt|))
|
||||||
|
R|/takePositive|(R|/select|<R|@Positive kotlin/Int|>(R|<local>/positiveInt|, R|<local>/positiveInt|))
|
||||||
|
R|/takePositive|(R|/select|<R|it(kotlin/Number & kotlin/Comparable<*>)|>(R|<local>/positiveInt|, R|<local>/positiveDouble|))
|
||||||
|
R|/takePositive|(R|/select|<R|it(kotlin/Number & kotlin/Comparable<*>)|>(R|<local>/positiveInt|, R|<local>/negativeDouble|))
|
||||||
|
R|/takeNegative|(R|/select|<R|it(kotlin/Number & kotlin/Comparable<*>)|>(R|<local>/positiveInt|, R|<local>/negativeDouble|))
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
import org.jetbrains.kotlin.fir.plugin.Positive
|
||||||
|
import org.jetbrains.kotlin.fir.plugin.Negative
|
||||||
|
|
||||||
|
fun takePositive(x: @Positive Number) {}
|
||||||
|
fun takeNegative(x: @Negative Number) {}
|
||||||
|
fun takeAny(x: Number) {}
|
||||||
|
|
||||||
|
fun <K> id(x: K): K = x
|
||||||
|
fun <K> select(x: K, y: K): K = x
|
||||||
|
|
||||||
|
fun test(
|
||||||
|
positiveInt: @Positive Int,
|
||||||
|
positiveDouble: @Positive Double,
|
||||||
|
negativeDouble: @Negative Double
|
||||||
|
) {
|
||||||
|
takePositive(positiveInt) // ok
|
||||||
|
takeNegative(negativeDouble) // ok
|
||||||
|
takeAny(positiveInt)
|
||||||
|
|
||||||
|
takePositive(<!ILLEGAL_NUMBER_SIGN!>negativeDouble<!>) // error
|
||||||
|
takeNegative(<!ILLEGAL_NUMBER_SIGN!>positiveInt<!>) // error
|
||||||
|
|
||||||
|
takePositive(id(positiveInt)) // ok
|
||||||
|
takeNegative(<!ILLEGAL_NUMBER_SIGN!>id(positiveInt)<!>) // error
|
||||||
|
|
||||||
|
takePositive(select(positiveInt, positiveInt)) // ok
|
||||||
|
// Should be ok, but currently attributes are not passed through common super type calculation
|
||||||
|
takePositive(<!ILLEGAL_NUMBER_SIGN!>select(positiveInt, positiveDouble)<!>)
|
||||||
|
takePositive(<!ILLEGAL_NUMBER_SIGN!>select(positiveInt, negativeDouble)<!>) // error
|
||||||
|
takeNegative(<!ILLEGAL_NUMBER_SIGN!>select(positiveInt, negativeDouble)<!>) // error
|
||||||
|
}
|
||||||
+6
@@ -33,6 +33,12 @@ public class FirAllOpenDiagnosticTestGenerated extends AbstractFirAllOpenDiagnos
|
|||||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/fir/fir-plugin-prototype/testData/checkers"), Pattern.compile("^(.+)\\.kt$"), null, true);
|
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/fir/fir-plugin-prototype/testData/checkers"), Pattern.compile("^(.+)\\.kt$"), null, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("signedNumbersCheckers.kt")
|
||||||
|
public void testSignedNumbersCheckers() throws Exception {
|
||||||
|
runTest("plugins/fir/fir-plugin-prototype/testData/checkers/signedNumbersCheckers.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("simple.kt")
|
@TestMetadata("simple.kt")
|
||||||
public void testSimple() throws Exception {
|
public void testSimple() throws Exception {
|
||||||
|
|||||||
Reference in New Issue
Block a user