[K2] Use file name as one of parameters to extract evaluated const
It is not enough to store evaluated constants only by <startOffset, endOffset> pair. We need to consider case there constant can be located in different files with the same offset but with different values. #KT-57928 Fixed #KT-57929 Fixed
This commit is contained in:
+4
-2
@@ -94,8 +94,10 @@ class FirElementSerializer private constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (file in files) {
|
for (file in files) {
|
||||||
for (declaration in file.declarations) {
|
extension.processFile(file) {
|
||||||
addDeclaration(declaration) {}
|
for (declaration in file.declarations) {
|
||||||
|
addDeclaration(declaration) {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+11
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.fir.serialization
|
|||||||
import org.jetbrains.kotlin.fir.FirSession
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
import org.jetbrains.kotlin.fir.declarations.*
|
import org.jetbrains.kotlin.fir.declarations.*
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
|
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
|
||||||
|
import org.jetbrains.kotlin.fir.serialization.constant.ConstValueProviderInternals
|
||||||
import org.jetbrains.kotlin.fir.serialization.constant.ConstValueProvider
|
import org.jetbrains.kotlin.fir.serialization.constant.ConstValueProvider
|
||||||
import org.jetbrains.kotlin.fir.types.ConeErrorType
|
import org.jetbrains.kotlin.fir.types.ConeErrorType
|
||||||
import org.jetbrains.kotlin.fir.types.ConeFlexibleType
|
import org.jetbrains.kotlin.fir.types.ConeFlexibleType
|
||||||
@@ -27,6 +28,16 @@ abstract class FirSerializerExtension {
|
|||||||
|
|
||||||
protected abstract val constValueProvider: ConstValueProvider?
|
protected abstract val constValueProvider: ConstValueProvider?
|
||||||
|
|
||||||
|
@OptIn(ConstValueProviderInternals::class)
|
||||||
|
internal inline fun <T> processFile(firFile: FirFile, action: () -> T): T {
|
||||||
|
constValueProvider?.processingFirFile = firFile
|
||||||
|
return try {
|
||||||
|
action()
|
||||||
|
} finally {
|
||||||
|
constValueProvider?.processingFirFile = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
open fun shouldUseTypeTable(): Boolean = false
|
open fun shouldUseTypeTable(): Boolean = false
|
||||||
open fun shouldUseNormalizedVisibility(): Boolean = false
|
open fun shouldUseNormalizedVisibility(): Boolean = false
|
||||||
|
|
||||||
|
|||||||
-1
@@ -95,7 +95,6 @@ abstract class FirSerializerExtensionBase(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun serializeTypeAnnotations(annotations: List<FirAnnotation>, proto: ProtoBuf.Type.Builder) {
|
override fun serializeTypeAnnotations(annotations: List<FirAnnotation>, proto: ProtoBuf.Type.Builder) {
|
||||||
// TODO support const extraction for type annotations
|
|
||||||
annotations.serializeAnnotations(proto, protocol.typeAnnotation)
|
annotations.serializeAnnotations(proto, protocol.typeAnnotation)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+11
@@ -8,11 +8,22 @@ package org.jetbrains.kotlin.fir.serialization.constant
|
|||||||
import org.jetbrains.kotlin.constant.ConstantValue
|
import org.jetbrains.kotlin.constant.ConstantValue
|
||||||
import org.jetbrains.kotlin.constant.EvaluatedConstTracker
|
import org.jetbrains.kotlin.constant.EvaluatedConstTracker
|
||||||
import org.jetbrains.kotlin.fir.FirSession
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.FirFile
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||||
|
|
||||||
|
@RequiresOptIn(
|
||||||
|
message = "Please note that this is internal API and it is supposed to be used with special conditions",
|
||||||
|
level = RequiresOptIn.Level.WARNING
|
||||||
|
)
|
||||||
|
annotation class ConstValueProviderInternals
|
||||||
|
|
||||||
abstract class ConstValueProvider {
|
abstract class ConstValueProvider {
|
||||||
abstract val session: FirSession
|
abstract val session: FirSession
|
||||||
abstract val evaluatedConstTracker: EvaluatedConstTracker
|
abstract val evaluatedConstTracker: EvaluatedConstTracker
|
||||||
|
|
||||||
|
var processingFirFile: FirFile? = null
|
||||||
|
@ConstValueProviderInternals
|
||||||
|
set
|
||||||
|
|
||||||
abstract fun findConstantValueFor(firExpression: FirExpression?): ConstantValue<*>?
|
abstract fun findConstantValueFor(firExpression: FirExpression?): ConstantValue<*>?
|
||||||
}
|
}
|
||||||
|
|||||||
+35
-24
@@ -27,28 +27,28 @@ import org.jetbrains.kotlin.types.ConstantValueKind
|
|||||||
|
|
||||||
internal fun FirExpression.toConstantValue(session: FirSession, constValueProvider: ConstValueProvider? = null): ConstantValue<*>? {
|
internal fun FirExpression.toConstantValue(session: FirSession, constValueProvider: ConstValueProvider? = null): ConstantValue<*>? {
|
||||||
constValueProvider?.findConstantValueFor(this)?.let { return it }
|
constValueProvider?.findConstantValueFor(this)?.let { return it }
|
||||||
return accept(FirToConstantValueTransformerUnsafe(constValueProvider), session)
|
return accept(FirToConstantValueTransformerUnsafe(), FirToConstantValueTransformerData(session, constValueProvider))
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun FirExpression?.hasConstantValue(session: FirSession): Boolean {
|
internal fun FirExpression?.hasConstantValue(session: FirSession): Boolean {
|
||||||
return this?.accept(FirToConstantValueChecker, session) == true
|
return this?.accept(FirToConstantValueChecker, session) == true
|
||||||
}
|
}
|
||||||
|
|
||||||
private class FirToConstantValueTransformerSafe(
|
private class FirToConstantValueTransformerSafe : FirToConstantValueTransformer(failOnNonConst = false)
|
||||||
constValueProvider: ConstValueProvider?
|
|
||||||
) : FirToConstantValueTransformer(failOnNonConst = false, constValueProvider)
|
|
||||||
|
|
||||||
private class FirToConstantValueTransformerUnsafe(
|
private class FirToConstantValueTransformerUnsafe : FirToConstantValueTransformer(failOnNonConst = true)
|
||||||
constValueProvider: ConstValueProvider?
|
|
||||||
) : FirToConstantValueTransformer(failOnNonConst = true, constValueProvider)
|
private data class FirToConstantValueTransformerData(
|
||||||
|
val session: FirSession,
|
||||||
|
val constValueProvider: ConstValueProvider?,
|
||||||
|
)
|
||||||
|
|
||||||
private abstract class FirToConstantValueTransformer(
|
private abstract class FirToConstantValueTransformer(
|
||||||
private val failOnNonConst: Boolean,
|
private val failOnNonConst: Boolean,
|
||||||
private val constValueProvider: ConstValueProvider?
|
) : FirDefaultVisitor<ConstantValue<*>?, FirToConstantValueTransformerData>() {
|
||||||
) : FirDefaultVisitor<ConstantValue<*>?, FirSession>() {
|
|
||||||
override fun visitElement(
|
override fun visitElement(
|
||||||
element: FirElement,
|
element: FirElement,
|
||||||
data: FirSession
|
data: FirToConstantValueTransformerData
|
||||||
): ConstantValue<*>? {
|
): ConstantValue<*>? {
|
||||||
if (failOnNonConst) {
|
if (failOnNonConst) {
|
||||||
error("Illegal element as annotation argument: ${element::class.qualifiedName} -> ${element.render()}")
|
error("Illegal element as annotation argument: ${element::class.qualifiedName} -> ${element.render()}")
|
||||||
@@ -58,7 +58,7 @@ private abstract class FirToConstantValueTransformer(
|
|||||||
|
|
||||||
override fun <T> visitConstExpression(
|
override fun <T> visitConstExpression(
|
||||||
constExpression: FirConstExpression<T>,
|
constExpression: FirConstExpression<T>,
|
||||||
data: FirSession
|
data: FirToConstantValueTransformerData
|
||||||
): ConstantValue<*>? {
|
): ConstantValue<*>? {
|
||||||
val value = constExpression.value
|
val value = constExpression.value
|
||||||
return when (constExpression.kind) {
|
return when (constExpression.kind) {
|
||||||
@@ -80,7 +80,10 @@ private abstract class FirToConstantValueTransformer(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitStringConcatenationCall(stringConcatenationCall: FirStringConcatenationCall, data: FirSession): ConstantValue<*>? {
|
override fun visitStringConcatenationCall(
|
||||||
|
stringConcatenationCall: FirStringConcatenationCall,
|
||||||
|
data: FirToConstantValueTransformerData
|
||||||
|
): ConstantValue<*>? {
|
||||||
val strings = stringConcatenationCall.argumentList.arguments.map { it.accept(this, data) }
|
val strings = stringConcatenationCall.argumentList.arguments.map { it.accept(this, data) }
|
||||||
if (strings.any { it == null || it !is StringValue }) return null
|
if (strings.any { it == null || it !is StringValue }) return null
|
||||||
return StringValue(strings.joinToString(separator = "") { (it as StringValue).value })
|
return StringValue(strings.joinToString(separator = "") { (it as StringValue).value })
|
||||||
@@ -88,33 +91,33 @@ private abstract class FirToConstantValueTransformer(
|
|||||||
|
|
||||||
override fun visitArrayOfCall(
|
override fun visitArrayOfCall(
|
||||||
arrayOfCall: FirArrayOfCall,
|
arrayOfCall: FirArrayOfCall,
|
||||||
data: FirSession
|
data: FirToConstantValueTransformerData
|
||||||
): ConstantValue<*> {
|
): ConstantValue<*> {
|
||||||
return ArrayValue(arrayOfCall.argumentList.arguments.mapNotNull { it.accept(this, data) })
|
return ArrayValue(arrayOfCall.argumentList.arguments.mapNotNull { it.accept(this, data) })
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitAnnotation(
|
override fun visitAnnotation(
|
||||||
annotation: FirAnnotation,
|
annotation: FirAnnotation,
|
||||||
data: FirSession
|
data: FirToConstantValueTransformerData
|
||||||
): ConstantValue<*> {
|
): ConstantValue<*> {
|
||||||
val mapping = annotation.argumentMapping.mapping.convertToConstantValues(data, constValueProvider)
|
val mapping = annotation.argumentMapping.mapping.convertToConstantValues(data.session, data.constValueProvider)
|
||||||
return AnnotationValue.create(annotation.annotationTypeRef.coneType, mapping)
|
return AnnotationValue.create(annotation.annotationTypeRef.coneType, mapping)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitAnnotationCall(annotationCall: FirAnnotationCall, data: FirSession): ConstantValue<*> {
|
override fun visitAnnotationCall(annotationCall: FirAnnotationCall, data: FirToConstantValueTransformerData): ConstantValue<*> {
|
||||||
return visitAnnotation(annotationCall, data)
|
return visitAnnotation(annotationCall, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitGetClassCall(
|
override fun visitGetClassCall(
|
||||||
getClassCall: FirGetClassCall,
|
getClassCall: FirGetClassCall,
|
||||||
data: FirSession
|
data: FirToConstantValueTransformerData
|
||||||
): ConstantValue<*>? {
|
): ConstantValue<*>? {
|
||||||
return create(getClassCall.argument.typeRef.coneTypeUnsafe())
|
return create(getClassCall.argument.typeRef.coneTypeUnsafe())
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitQualifiedAccessExpression(
|
override fun visitQualifiedAccessExpression(
|
||||||
qualifiedAccessExpression: FirQualifiedAccessExpression,
|
qualifiedAccessExpression: FirQualifiedAccessExpression,
|
||||||
data: FirSession
|
data: FirToConstantValueTransformerData
|
||||||
): ConstantValue<*>? {
|
): ConstantValue<*>? {
|
||||||
val symbol = qualifiedAccessExpression.toResolvedCallableSymbol() ?: return null
|
val symbol = qualifiedAccessExpression.toResolvedCallableSymbol() ?: return null
|
||||||
val fir = symbol.fir
|
val fir = symbol.fir
|
||||||
@@ -139,10 +142,12 @@ private abstract class FirToConstantValueTransformer(
|
|||||||
|
|
||||||
symbol is FirConstructorSymbol -> {
|
symbol is FirConstructorSymbol -> {
|
||||||
val constructorCall = qualifiedAccessExpression as FirFunctionCall
|
val constructorCall = qualifiedAccessExpression as FirFunctionCall
|
||||||
val constructedClassSymbol = symbol.containingClassLookupTag()?.toFirRegularClassSymbol(data) ?: return null
|
val constructedClassSymbol = symbol.containingClassLookupTag()?.toFirRegularClassSymbol(data.session) ?: return null
|
||||||
if (constructedClassSymbol.classKind != ClassKind.ANNOTATION_CLASS) return null
|
if (constructedClassSymbol.classKind != ClassKind.ANNOTATION_CLASS) return null
|
||||||
|
|
||||||
val mapping = constructorCall.resolvedArgumentMapping?.convertToConstantValues(data, constValueProvider) ?: return null
|
val mapping = constructorCall.resolvedArgumentMapping
|
||||||
|
?.convertToConstantValues(data.session, data.constValueProvider)
|
||||||
|
?: return null
|
||||||
return AnnotationValue.create(qualifiedAccessExpression.typeRef.coneType, mapping)
|
return AnnotationValue.create(qualifiedAccessExpression.typeRef.coneType, mapping)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -174,13 +179,16 @@ private abstract class FirToConstantValueTransformer(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitPropertyAccessExpression(propertyAccessExpression: FirPropertyAccessExpression, data: FirSession): ConstantValue<*>? {
|
override fun visitPropertyAccessExpression(
|
||||||
|
propertyAccessExpression: FirPropertyAccessExpression,
|
||||||
|
data: FirToConstantValueTransformerData
|
||||||
|
): ConstantValue<*>? {
|
||||||
return visitQualifiedAccessExpression(propertyAccessExpression, data)
|
return visitQualifiedAccessExpression(propertyAccessExpression, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitFunctionCall(
|
override fun visitFunctionCall(
|
||||||
functionCall: FirFunctionCall,
|
functionCall: FirFunctionCall,
|
||||||
data: FirSession
|
data: FirToConstantValueTransformerData
|
||||||
): ConstantValue<*>? {
|
): ConstantValue<*>? {
|
||||||
if (functionCall.isArrayOfCall) {
|
if (functionCall.isArrayOfCall) {
|
||||||
return FirArrayOfCallTransformer().transformFunctionCall(functionCall, null).accept(this, data)
|
return FirArrayOfCallTransformer().transformFunctionCall(functionCall, null).accept(this, data)
|
||||||
@@ -190,12 +198,15 @@ private abstract class FirToConstantValueTransformer(
|
|||||||
|
|
||||||
override fun visitVarargArgumentsExpression(
|
override fun visitVarargArgumentsExpression(
|
||||||
varargArgumentsExpression: FirVarargArgumentsExpression,
|
varargArgumentsExpression: FirVarargArgumentsExpression,
|
||||||
data: FirSession
|
data: FirToConstantValueTransformerData
|
||||||
): ConstantValue<*> {
|
): ConstantValue<*> {
|
||||||
return ArrayValue(varargArgumentsExpression.arguments.mapNotNull { it.accept(this, data) })
|
return ArrayValue(varargArgumentsExpression.arguments.mapNotNull { it.accept(this, data) })
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitNamedArgumentExpression(namedArgumentExpression: FirNamedArgumentExpression, data: FirSession): ConstantValue<*>? {
|
override fun visitNamedArgumentExpression(
|
||||||
|
namedArgumentExpression: FirNamedArgumentExpression,
|
||||||
|
data: FirToConstantValueTransformerData
|
||||||
|
): ConstantValue<*>? {
|
||||||
return namedArgumentExpression.expression.accept(this, data)
|
return namedArgumentExpression.expression.accept(this, data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -46,7 +46,7 @@ fun serializeSingleFirFile(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val classesProto = file.declarations.makeClassesProtoWithNested()
|
val classesProto = serializerExtension.processFile(file) { file.declarations.makeClassesProtoWithNested() }
|
||||||
|
|
||||||
val hasTopLevelDeclarations = file.declarations.any {
|
val hasTopLevelDeclarations = file.declarations.any {
|
||||||
it is FirMemberDeclaration && it.shouldBeSerialized(actualizedExpectDeclarations) &&
|
it is FirMemberDeclaration && it.shouldBeSerialized(actualizedExpectDeclarations) &&
|
||||||
|
|||||||
@@ -10,7 +10,9 @@ import org.jetbrains.kotlin.constant.EvaluatedConstTracker
|
|||||||
import org.jetbrains.kotlin.fir.FirSession
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
|
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
|
||||||
|
import org.jetbrains.kotlin.fir.packageFqName
|
||||||
import org.jetbrains.kotlin.fir.serialization.constant.ConstValueProvider
|
import org.jetbrains.kotlin.fir.serialization.constant.ConstValueProvider
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
|
||||||
class ConstValueProviderImpl(
|
class ConstValueProviderImpl(
|
||||||
components: Fir2IrComponents,
|
components: Fir2IrComponents,
|
||||||
@@ -19,18 +21,20 @@ class ConstValueProviderImpl(
|
|||||||
override val evaluatedConstTracker: EvaluatedConstTracker = components.configuration.evaluatedConstTracker
|
override val evaluatedConstTracker: EvaluatedConstTracker = components.configuration.evaluatedConstTracker
|
||||||
|
|
||||||
override fun findConstantValueFor(firExpression: FirExpression?): ConstantValue<*>? {
|
override fun findConstantValueFor(firExpression: FirExpression?): ConstantValue<*>? {
|
||||||
if (firExpression == null) return null
|
val firFile = processingFirFile
|
||||||
|
if (firExpression == null || firFile == null) return null
|
||||||
|
|
||||||
|
val fileName = firFile.packageFqName.child(Name.identifier(firFile.name)).asString()
|
||||||
return if (firExpression is FirQualifiedAccessExpression) {
|
return if (firExpression is FirQualifiedAccessExpression) {
|
||||||
// TODO check that this behavior is expected in ConversionUtils and if not fix it
|
// TODO check that this behavior is expected in ConversionUtils and if not fix it
|
||||||
val calleeReference = firExpression.calleeReference
|
val calleeReference = firExpression.calleeReference
|
||||||
val start = calleeReference.source?.startOffsetSkippingComments() ?: calleeReference.source?.startOffset ?: return null
|
val start = calleeReference.source?.startOffsetSkippingComments() ?: calleeReference.source?.startOffset ?: return null
|
||||||
val end = firExpression.source?.endOffset ?: return null
|
val end = firExpression.source?.endOffset ?: return null
|
||||||
evaluatedConstTracker.load(start, end)
|
evaluatedConstTracker.load(start, end, fileName)
|
||||||
} else {
|
} else {
|
||||||
val start = firExpression.source?.startOffset ?: return null
|
val start = firExpression.source?.startOffset ?: return null
|
||||||
val end = firExpression.source?.endOffset ?: return null
|
val end = firExpression.source?.endOffset ?: return null
|
||||||
evaluatedConstTracker.load(start, end)
|
evaluatedConstTracker.load(start, end, fileName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+2
-1
@@ -19,6 +19,7 @@ import org.jetbrains.kotlin.ir.interpreter.isPrimitiveArray
|
|||||||
import org.jetbrains.kotlin.ir.types.*
|
import org.jetbrains.kotlin.ir.types.*
|
||||||
import org.jetbrains.kotlin.ir.util.dump
|
import org.jetbrains.kotlin.ir.util.dump
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
|
|
||||||
@@ -76,7 +77,7 @@ class IrConstTransformer(
|
|||||||
}
|
}
|
||||||
|
|
||||||
evaluatedConstTracker?.save(
|
evaluatedConstTracker?.save(
|
||||||
result.startOffset, result.endOffset,
|
result.startOffset, result.endOffset, irFile.fqName.child(Name.identifier(irFile.name)).asString(),
|
||||||
constant = if (result is IrErrorExpression) ErrorValue.create(result.description)
|
constant = if (result is IrErrorExpression) ErrorValue.create(result.description)
|
||||||
else (result as IrConst<*>).toConstantValue()
|
else (result as IrConst<*>).toConstantValue()
|
||||||
)
|
)
|
||||||
|
|||||||
+1
-2
@@ -4,8 +4,7 @@ annotation class Key(val value: String)
|
|||||||
object Messanger {
|
object Messanger {
|
||||||
const val DEFAULT_TEXT = <!EVALUATED("OK")!>"OK"<!>
|
const val DEFAULT_TEXT = <!EVALUATED("OK")!>"OK"<!>
|
||||||
|
|
||||||
// Note: second `EVALUATED` from `message$default`
|
fun message(@Key(value = <!EVALUATED("OK")!>DEFAULT_TEXT<!>) text: String = <!EVALUATED("OK")!>DEFAULT_TEXT<!>): String {
|
||||||
fun message(@Key(value = <!EVALUATED("OK"), EVALUATED("OK")!>DEFAULT_TEXT<!>) text: String = <!EVALUATED("OK")!>DEFAULT_TEXT<!>): String {
|
|
||||||
return text
|
return text
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+22
-10
@@ -50,17 +50,16 @@ enum class SomeEnum {
|
|||||||
B;
|
B;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: can be uncommented after fix KT-57135
|
@field:BinaryAnnotation("Str" <!EVALUATED("String")!>+ "ing"<!>)
|
||||||
//@field:BinaryAnnotation("Str" + "ing")
|
var x: Int = 5
|
||||||
//var x: Int = 5
|
|
||||||
|
|
||||||
//object Delegate {
|
object Delegate {
|
||||||
// operator fun getValue(instance: Any?, property: Any) : String = ""
|
operator fun getValue(instance: Any?, property: Any) : String = ""
|
||||||
// operator fun setValue(instance: Any?, property: Any, value: String) {}
|
operator fun setValue(instance: Any?, property: Any, value: String) {}
|
||||||
//}
|
}
|
||||||
//
|
|
||||||
//@delegate:BinaryAnnotation("Str" + "ing")
|
@delegate:BinaryAnnotation("Str" <!EVALUATED("String")!>+ "ing"<!>)
|
||||||
//val p: String by Delegate
|
val p: String by Delegate
|
||||||
|
|
||||||
|
|
||||||
// 7. VALUE_PARAMETER
|
// 7. VALUE_PARAMETER
|
||||||
@@ -70,6 +69,19 @@ fun foo(@BinaryAnnotation("Str" <!EVALUATED("String")!>+ "ing"<!>) a: Int) { }
|
|||||||
val @receiver:BinaryAnnotation("Str" <!EVALUATED("String")!>+ "ing"<!>) String.a: Int
|
val @receiver:BinaryAnnotation("Str" <!EVALUATED("String")!>+ "ing"<!>) String.a: Int
|
||||||
get() = 0
|
get() = 0
|
||||||
|
|
||||||
|
class WithConstructorArgumentAnnotation(
|
||||||
|
@BinaryAnnotation("Str" <!EVALUATED("String")!>+ "ing"<!>)
|
||||||
|
val a: Int
|
||||||
|
)
|
||||||
|
|
||||||
|
@setparam:BinaryAnnotation("Str" <!EVALUATED("String")!>+ "ing"<!>)
|
||||||
|
var setParamProp: Int = 0
|
||||||
|
get() = field + 1
|
||||||
|
set(x: Int) { field = x * 2 }
|
||||||
|
|
||||||
|
var mutablePropWithAnnotationOnSetterParam = 0
|
||||||
|
set(@BinaryAnnotation("Str" <!EVALUATED("String")!>+ "ing"<!>) x: Int) { field = x * 2 }
|
||||||
|
|
||||||
// 9. FUNCTION
|
// 9. FUNCTION
|
||||||
@BinaryAnnotation("Str" <!EVALUATED("String")!>+ "ing"<!>)
|
@BinaryAnnotation("Str" <!EVALUATED("String")!>+ "ing"<!>)
|
||||||
fun bar() {}
|
fun bar() {}
|
||||||
|
|||||||
Vendored
+1
-1
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
@Target(AnnotationTarget.CLASS)
|
@Target(AnnotationTarget.CLASS)
|
||||||
@Retention(AnnotationRetention.BINARY)
|
@Retention(AnnotationRetention.BINARY)
|
||||||
annotation class AnnotationWithDefault(val str: String = "Str" + "ing")
|
annotation class AnnotationWithDefault(val str: String = "Str" <!EVALUATED("String")!>+ "ing"<!>)
|
||||||
|
|
||||||
@AnnotationWithDefault()
|
@AnnotationWithDefault()
|
||||||
class A
|
class A
|
||||||
|
|||||||
+14
-48
@@ -6,20 +6,12 @@
|
|||||||
package org.jetbrains.kotlin.test.backend.handlers
|
package org.jetbrains.kotlin.test.backend.handlers
|
||||||
|
|
||||||
import com.intellij.openapi.util.text.StringUtil
|
import com.intellij.openapi.util.text.StringUtil
|
||||||
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
|
|
||||||
import org.jetbrains.kotlin.codeMetaInfo.model.ParsedCodeMetaInfo
|
import org.jetbrains.kotlin.codeMetaInfo.model.ParsedCodeMetaInfo
|
||||||
import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
||||||
import org.jetbrains.kotlin.constant.ErrorValue
|
import org.jetbrains.kotlin.constant.ErrorValue
|
||||||
import org.jetbrains.kotlin.constant.EvaluatedConstTracker
|
import org.jetbrains.kotlin.constant.EvaluatedConstTracker
|
||||||
import org.jetbrains.kotlin.ir.IrElement
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrAnnotationContainer
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationBase
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrField
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrConst
|
import org.jetbrains.kotlin.ir.declarations.name
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
|
||||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
|
||||||
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
|
||||||
import org.jetbrains.kotlin.test.TargetBackend
|
import org.jetbrains.kotlin.test.TargetBackend
|
||||||
import org.jetbrains.kotlin.test.directives.CodegenTestDirectives.IGNORE_BACKEND_K2
|
import org.jetbrains.kotlin.test.directives.CodegenTestDirectives.IGNORE_BACKEND_K2
|
||||||
import org.jetbrains.kotlin.test.model.*
|
import org.jetbrains.kotlin.test.model.*
|
||||||
@@ -44,7 +36,7 @@ interface IrInterpreterDumpHandler {
|
|||||||
val evaluatedConstTracker = configuration.get(CommonConfigurationKeys.EVALUATED_CONST_TRACKER) ?: return
|
val evaluatedConstTracker = configuration.get(CommonConfigurationKeys.EVALUATED_CONST_TRACKER) ?: return
|
||||||
val irModule = testServices.dependencyProvider.getArtifact(module, BackendKinds.IrBackend).irModuleFragment
|
val irModule = testServices.dependencyProvider.getArtifact(module, BackendKinds.IrBackend).irModuleFragment
|
||||||
for ((irFile, testFile) in matchIrFileWithTestFile(irModule, module)) {
|
for ((irFile, testFile) in matchIrFileWithTestFile(irModule, module)) {
|
||||||
evaluatedConstTracker.processFile(testFile, irFile, testServices.defaultsProvider.defaultTargetBackend ?: module.targetBackend)
|
evaluatedConstTracker.processFile(testFile, irFile)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,44 +46,18 @@ interface IrInterpreterDumpHandler {
|
|||||||
return targetBackend in ignoredBackends || TargetBackend.ANY in ignoredBackends
|
return targetBackend in ignoredBackends || TargetBackend.ANY in ignoredBackends
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun EvaluatedConstTracker.processFile(testFile: TestFile, irFile: IrFile, targetBackend: TargetBackend?) {
|
private fun EvaluatedConstTracker.processFile(testFile: TestFile, irFile: IrFile) {
|
||||||
irFile.accept(object : IrElementVisitorVoid {
|
this.load(irFile.name)?.forEach { (pair, constantValue) ->
|
||||||
override fun visitElement(element: IrElement) {
|
val (start, end) = pair
|
||||||
element.acceptChildrenVoid(this)
|
val message = constantValue.stringTemplateValue()
|
||||||
}
|
val metaInfo = ParsedCodeMetaInfo(
|
||||||
|
start, end,
|
||||||
override fun visitDeclaration(declaration: IrDeclarationBase) {
|
attributes = mutableListOf(),
|
||||||
if (declaration.origin == JvmLoweredDeclarationOrigin.SYNTHETIC_METHOD_FOR_PROPERTY_OR_TYPEALIAS_ANNOTATIONS) return
|
tag = if (constantValue is ErrorValue) "WAS_NOT_EVALUATED" else "EVALUATED",
|
||||||
visitAnnotations(declaration)
|
description = StringUtil.escapeLineBreak(message)
|
||||||
super.visitDeclaration(declaration)
|
)
|
||||||
}
|
globalMetadataInfoHandler.addMetadataInfosForFile(testFile, listOf(metaInfo))
|
||||||
|
}
|
||||||
// TODO can be dropped if we are going to draw one info per line segment
|
|
||||||
override fun visitField(declaration: IrField) {
|
|
||||||
if (targetBackend == TargetBackend.JVM_IR) {
|
|
||||||
declaration.correspondingPropertySymbol?.owner?.let { visitAnnotations(it) }
|
|
||||||
}
|
|
||||||
super.visitField(declaration)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun visitAnnotations(annotationContainer: IrAnnotationContainer) {
|
|
||||||
annotationContainer.annotations.forEach { annotation ->
|
|
||||||
annotation.acceptVoid(this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitConst(expression: IrConst<*>) {
|
|
||||||
val constantValue = this@processFile.load(expression.startOffset, expression.endOffset) ?: return
|
|
||||||
val message = constantValue.stringTemplateValue()
|
|
||||||
val metaInfo = ParsedCodeMetaInfo(
|
|
||||||
expression.startOffset, expression.endOffset,
|
|
||||||
attributes = mutableListOf(),
|
|
||||||
tag = if (constantValue is ErrorValue) "WAS_NOT_EVALUATED" else "EVALUATED",
|
|
||||||
description = StringUtil.escapeLineBreak(message)
|
|
||||||
)
|
|
||||||
globalMetadataInfoHandler.addMetadataInfosForFile(testFile, listOf(metaInfo))
|
|
||||||
}
|
|
||||||
}, null)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,8 +8,9 @@ package org.jetbrains.kotlin.constant
|
|||||||
import java.util.concurrent.ConcurrentHashMap
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
|
|
||||||
abstract class EvaluatedConstTracker {
|
abstract class EvaluatedConstTracker {
|
||||||
abstract fun save(start: Int, end: Int, constant: ConstantValue<*>)
|
abstract fun save(start: Int, end: Int, file: String, constant: ConstantValue<*>)
|
||||||
abstract fun load(start: Int, end: Int): ConstantValue<*>?
|
abstract fun load(start: Int, end: Int, file: String): ConstantValue<*>?
|
||||||
|
abstract fun load(file: String): Map<Pair<Int, Int>, ConstantValue<*>>?
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
/**
|
/**
|
||||||
@@ -24,14 +25,20 @@ abstract class EvaluatedConstTracker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private class DefaultEvaluatedConstTracker : EvaluatedConstTracker() {
|
private class DefaultEvaluatedConstTracker : EvaluatedConstTracker() {
|
||||||
private val storage = ConcurrentHashMap<Pair<Int, Int>, ConstantValue<*>>()
|
private val storage = ConcurrentHashMap<String, ConcurrentHashMap<Pair<Int, Int>, ConstantValue<*>>>()
|
||||||
|
|
||||||
override fun save(start: Int, end: Int, constant: ConstantValue<*>) {
|
override fun save(start: Int, end: Int, file: String, constant: ConstantValue<*>) {
|
||||||
storage[start to end] = constant
|
storage
|
||||||
|
.getOrPut(file) { ConcurrentHashMap() }
|
||||||
|
.let { it[start to end] = constant }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun load(start: Int, end: Int): ConstantValue<*>? {
|
override fun load(start: Int, end: Int, file: String): ConstantValue<*>? {
|
||||||
return storage[start to end]
|
return storage[file]?.get(start to end)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun load(file: String): Map<Pair<Int, Int>, ConstantValue<*>>? {
|
||||||
|
return storage[file]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user