[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:
Ivan Kylchik
2023-04-11 12:56:59 +02:00
committed by Space Team
parent 8cc8e54a9f
commit c00c7ffbe0
13 changed files with 123 additions and 100 deletions
@@ -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) {}
}
} }
} }
@@ -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
@@ -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)
} }
@@ -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<*>?
} }
@@ -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)
} }
} }
@@ -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)
} }
} }
} }
@@ -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()
) )
@@ -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
} }
} }
@@ -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() {}
@@ -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
@@ -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]
} }
} }