FIR tree: support const expressions (adds IR dependency) #KT-24023 Fixed
Also support generic tree elements in FIR visitor generator
This commit is contained in:
@@ -14,6 +14,7 @@ dependencies {
|
|||||||
compile(project(":compiler:psi"))
|
compile(project(":compiler:psi"))
|
||||||
compile(project(":core:descriptors"))
|
compile(project(":core:descriptors"))
|
||||||
compile(project(":compiler:fir:tree"))
|
compile(project(":compiler:fir:tree"))
|
||||||
|
compile(project(":compiler:ir.tree"))
|
||||||
|
|
||||||
compileOnly(intellijCoreDep()) { includeJars("intellij-core", "annotations") }
|
compileOnly(intellijCoreDep()) { includeJars("intellij-core", "annotations") }
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.fir.builder
|
package org.jetbrains.kotlin.fir.builder
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.KtNodeTypes
|
||||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||||
import org.jetbrains.kotlin.descriptors.Modality
|
import org.jetbrains.kotlin.descriptors.Modality
|
||||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||||
@@ -24,6 +25,7 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
|
|||||||
import org.jetbrains.kotlin.fir.types.FirType
|
import org.jetbrains.kotlin.fir.types.FirType
|
||||||
import org.jetbrains.kotlin.fir.types.FirTypeProjection
|
import org.jetbrains.kotlin.fir.types.FirTypeProjection
|
||||||
import org.jetbrains.kotlin.fir.types.impl.*
|
import org.jetbrains.kotlin.fir.types.impl.*
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrConstKind
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens.*
|
import org.jetbrains.kotlin.lexer.KtTokens.*
|
||||||
import org.jetbrains.kotlin.name.ClassId
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
@@ -91,8 +93,127 @@ class RawFirBuilder(val session: FirSession) {
|
|||||||
else -> FirExpressionBodyImpl(session, FirExpressionStub(session, null))
|
else -> FirExpressionBodyImpl(session, FirExpressionStub(session, null))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ValueArgument?.toFirExpression(): FirExpression = with(this as? KtElement) {
|
private fun String.parseCharacter(): Char? {
|
||||||
convertSafe() ?: FirErrorExpressionImpl(session, this)
|
// Strip the quotes
|
||||||
|
if (length < 2 || this[0] != '\'' || this[length - 1] != '\'') {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
val text = substring(1, length - 1) // now there're no quotes
|
||||||
|
|
||||||
|
if (text.isEmpty()) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return if (text[0] != '\\') {
|
||||||
|
// No escape
|
||||||
|
if (text.length == 1) {
|
||||||
|
text[0]
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
escapedStringToCharacter(text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun escapedStringToCharacter(text: String): Char? {
|
||||||
|
assert(text.isNotEmpty() && text[0] == '\\') {
|
||||||
|
"Only escaped sequences must be passed to this routine: $text"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Escape
|
||||||
|
val escape = text.substring(1) // strip the slash
|
||||||
|
when (escape.length) {
|
||||||
|
0 -> {
|
||||||
|
// bare slash
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
1 -> {
|
||||||
|
// one-char escape
|
||||||
|
return translateEscape(escape[0]) ?: return null
|
||||||
|
}
|
||||||
|
5 -> {
|
||||||
|
// unicode escape
|
||||||
|
if (escape[0] == 'u') {
|
||||||
|
try {
|
||||||
|
val intValue = Integer.valueOf(escape.substring(1), 16)
|
||||||
|
return intValue.toInt().toChar()
|
||||||
|
} catch (e: NumberFormatException) {
|
||||||
|
// Will be reported below
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun translateEscape(c: Char): Char? =
|
||||||
|
when (c) {
|
||||||
|
't' -> '\t'
|
||||||
|
'b' -> '\b'
|
||||||
|
'n' -> '\n'
|
||||||
|
'r' -> '\r'
|
||||||
|
'\'' -> '\''
|
||||||
|
'\"' -> '\"'
|
||||||
|
'\\' -> '\\'
|
||||||
|
'$' -> '$'
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun ValueArgument?.toFirExpression(): FirExpression {
|
||||||
|
this ?: return FirErrorExpressionImpl(session, this as? KtElement, "No argument given")
|
||||||
|
val expression = this.getArgumentExpression()
|
||||||
|
when (expression) {
|
||||||
|
is KtConstantExpression -> {
|
||||||
|
val type = expression.node.elementType
|
||||||
|
val text: String = expression.text
|
||||||
|
return when (type) {
|
||||||
|
KtNodeTypes.INTEGER_CONSTANT ->
|
||||||
|
if (text.last() == 'l' || text.last() == 'L') {
|
||||||
|
FirConstExpressionImpl(
|
||||||
|
session, expression, IrConstKind.Long, text.dropLast(1).toLongOrNull(), "Incorrect long: $text"
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
// TODO: support byte / short
|
||||||
|
FirConstExpressionImpl(session, expression, IrConstKind.Int, text.toIntOrNull(), "Incorrect int: $text")
|
||||||
|
}
|
||||||
|
KtNodeTypes.FLOAT_CONSTANT ->
|
||||||
|
if (text.last() == 'f' || text.last() == 'F') {
|
||||||
|
FirConstExpressionImpl(
|
||||||
|
session, expression, IrConstKind.Float, text.dropLast(1).toFloatOrNull(), "Incorrect float: $text"
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
FirConstExpressionImpl(
|
||||||
|
session, expression, IrConstKind.Double, text.toDoubleOrNull(), "Incorrect double: $text"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
KtNodeTypes.CHARACTER_CONSTANT ->
|
||||||
|
FirConstExpressionImpl(
|
||||||
|
session, expression, IrConstKind.Char, text.parseCharacter(), "Incorrect character: $text"
|
||||||
|
)
|
||||||
|
KtNodeTypes.BOOLEAN_CONSTANT ->
|
||||||
|
FirConstExpressionImpl(session, expression, IrConstKind.Boolean, text.toBoolean())
|
||||||
|
KtNodeTypes.NULL ->
|
||||||
|
FirConstExpressionImpl(session, expression, IrConstKind.Null, null)
|
||||||
|
else ->
|
||||||
|
throw AssertionError("Unknown literal type: $type, $text")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
is KtStringTemplateExpression -> {
|
||||||
|
val sb = StringBuilder()
|
||||||
|
for (entry in expression.entries) {
|
||||||
|
when (entry) {
|
||||||
|
is KtLiteralStringTemplateEntry -> sb.append(entry.text)
|
||||||
|
is KtEscapeStringTemplateEntry -> sb.append(entry.unescapedValue)
|
||||||
|
else -> return FirErrorExpressionImpl(session, expression, "Incorrect template entry: ${entry.text}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return FirConstExpressionImpl(session, expression, IrConstKind.String, sb.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> return FirExpressionStub(session, this as? KtElement)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun KtPropertyAccessor?.toFirPropertyAccessor(
|
private fun KtPropertyAccessor?.toFirPropertyAccessor(
|
||||||
|
|||||||
@@ -8,3 +8,5 @@ annotation class WithInt(val value: Int)
|
|||||||
annotation class WithString(val s: String)
|
annotation class WithString(val s: String)
|
||||||
|
|
||||||
annotation class Complex(val wi: WithInt, val ws: WithString)
|
annotation class Complex(val wi: WithInt, val ws: WithString)
|
||||||
|
|
||||||
|
annotation class VeryComplex(val f: Float, val d: Double, val b: Boolean, val l: Long, val n: Int?)
|
||||||
@@ -25,4 +25,5 @@ class Second(val y: Char) : @WithInt(0) First() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@WithInt(24)
|
@WithInt(24)
|
||||||
|
@VeryComplex(3.14f, 6.67e-11, false, 123456789012345L, null)
|
||||||
typealias Third = @Simple Second
|
typealias Third = @Simple Second
|
||||||
@@ -1,16 +1,16 @@
|
|||||||
FILE: Annotations.kt
|
FILE: Annotations.kt
|
||||||
@FILE:R|annotations/Simple|()
|
@FILE:R|annotations/Simple|()
|
||||||
@R|annotations/WithInt|(STUB) public abstract class First {
|
@R|annotations/WithInt|(Int(42)) public abstract class First {
|
||||||
public constructor(): super<R|kotlin/Any|>()
|
public constructor(): super<R|kotlin/Any|>()
|
||||||
|
|
||||||
@R|annotations/Simple|() public abstract function foo(@R|annotations/WithString|(STUB) arg: @R|annotations/Simple|() R|kotlin/Double|): R|kotlin/Unit|
|
@R|annotations/Simple|() public abstract function foo(@R|annotations/WithString|(String(abc)) arg: @R|annotations/Simple|() R|kotlin/Double|): R|kotlin/Unit|
|
||||||
|
|
||||||
@R|annotations/Complex|(STUB, STUB) public abstract property v(val): R|kotlin/String|
|
@R|annotations/Complex|(STUB, STUB) public abstract property v(val): R|kotlin/String|
|
||||||
public get(): R|kotlin/String|
|
public get(): R|kotlin/String|
|
||||||
|
|
||||||
}
|
}
|
||||||
@R|annotations/WithString|(STUB) public final class Second : @R|annotations/WithInt|(STUB) R|test/First| {
|
@R|annotations/WithString|(String(xyz)) public final class Second : @R|annotations/WithInt|(Int(0)) R|test/First| {
|
||||||
public constructor(y: R|kotlin/Char|): super<@R|annotations/WithInt|(STUB) R|test/First|>()
|
public constructor(y: R|kotlin/Char|): super<@R|annotations/WithInt|(Int(0)) R|test/First|>()
|
||||||
|
|
||||||
public final property y(val): R|kotlin/Char|
|
public final property y(val): R|kotlin/Char|
|
||||||
public get(): R|kotlin/Char|
|
public get(): R|kotlin/Char|
|
||||||
@@ -23,7 +23,7 @@ FILE: Annotations.kt
|
|||||||
STUB
|
STUB
|
||||||
}
|
}
|
||||||
|
|
||||||
@R|annotations/WithString|(STUB) public constructor(): this<R|test/Second|>()
|
@R|annotations/WithString|(String(constructor)) public constructor(): this<R|test/Second|>()
|
||||||
|
|
||||||
}
|
}
|
||||||
@R|annotations/WithInt|(STUB) @R|annotations/WithInt|(STUB) public final typealias Third = @R|annotations/Simple|() R|test/Second|
|
@R|annotations/WithInt|(Int(24)) @R|annotations/VeryComplex|(Float(3.14), Double(6.67E-11), Boolean(false), Long(123456789012345), Null(null)) @R|annotations/WithInt|(Int(24)) @R|annotations/VeryComplex|(Float(3.14), Double(6.67E-11), Boolean(false), Long(123456789012345), Null(null)) public final typealias Third = @R|annotations/Simple|() R|test/Second|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ jvmTarget = "1.6"
|
|||||||
dependencies {
|
dependencies {
|
||||||
compile(project(":core:descriptors"))
|
compile(project(":core:descriptors"))
|
||||||
compile(project(":compiler:fir:cones"))
|
compile(project(":compiler:fir:cones"))
|
||||||
|
compile(project(":compiler:ir.tree"))
|
||||||
// Necessary only to store bound PsiElement inside FirElement
|
// Necessary only to store bound PsiElement inside FirElement
|
||||||
compileOnly(intellijCoreDep()) { includeJars("intellij-core", "annotations") }
|
compileOnly(intellijCoreDep()) { includeJars("intellij-core", "annotations") }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -361,6 +361,10 @@ class FirRenderer(builder: StringBuilder) : FirVisitorVoid() {
|
|||||||
print("STUB")
|
print("STUB")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun <T> visitConstExpression(constExpression: FirConstExpression<T>) {
|
||||||
|
print("${constExpression.kind}(${constExpression.value})")
|
||||||
|
}
|
||||||
|
|
||||||
override fun visitCall(call: FirCall) {
|
override fun visitCall(call: FirCall) {
|
||||||
print("(")
|
print("(")
|
||||||
call.arguments.renderSeparated()
|
call.arguments.renderSeparated()
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2018 JetBrains s.r.o. 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.expressions
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.fir.visitors.FirVisitor
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrConstKind
|
||||||
|
|
||||||
|
interface FirConstExpression<T> : FirExpression {
|
||||||
|
val kind: IrConstKind<T>
|
||||||
|
val value: T
|
||||||
|
|
||||||
|
override fun <R, D> accept(visitor: FirVisitor<R, D>, data: D): R {
|
||||||
|
return visitor.visitConstExpression(this, data)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,4 +5,6 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.fir.expressions
|
package org.jetbrains.kotlin.fir.expressions
|
||||||
|
|
||||||
interface FirErrorExpression : FirExpression
|
interface FirErrorExpression : FirExpression {
|
||||||
|
val reason: String
|
||||||
|
}
|
||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2018 JetBrains s.r.o. 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.expressions.impl
|
||||||
|
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.FirConstExpression
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrConstKind
|
||||||
|
|
||||||
|
class FirConstExpressionImpl<T>(
|
||||||
|
override val session: FirSession,
|
||||||
|
override val psi: PsiElement?,
|
||||||
|
override val kind: IrConstKind<T>,
|
||||||
|
override val value: T
|
||||||
|
) : FirConstExpression<T>
|
||||||
|
|
||||||
|
fun <T> FirConstExpressionImpl(session: FirSession, psi: PsiElement?, kind: IrConstKind<T>, value: T?, errorReason: String) =
|
||||||
|
value?.let { FirConstExpressionImpl(session, psi, kind, it) } ?: FirErrorExpressionImpl(session, psi, errorReason)
|
||||||
+2
-1
@@ -11,5 +11,6 @@ import org.jetbrains.kotlin.fir.expressions.FirErrorExpression
|
|||||||
|
|
||||||
class FirErrorExpressionImpl(
|
class FirErrorExpressionImpl(
|
||||||
override val session: FirSession,
|
override val session: FirSession,
|
||||||
override val psi: PsiElement?
|
override val psi: PsiElement?,
|
||||||
|
override val reason: String
|
||||||
) : FirErrorExpression
|
) : FirErrorExpression
|
||||||
@@ -10,7 +10,7 @@ import org.jetbrains.kotlin.utils.Printer
|
|||||||
abstract class AbstractVisitorGenerator(val referencesData: DataCollector.ReferencesData) {
|
abstract class AbstractVisitorGenerator(val referencesData: DataCollector.ReferencesData) {
|
||||||
fun Printer.generateFunction(
|
fun Printer.generateFunction(
|
||||||
name: String,
|
name: String,
|
||||||
parameters: Map<String, String>,
|
parameters: Map<String, DataCollector.NameWithTypeParameters>,
|
||||||
returnType: String,
|
returnType: String,
|
||||||
override: Boolean = false,
|
override: Boolean = false,
|
||||||
final: Boolean = false,
|
final: Boolean = false,
|
||||||
@@ -74,7 +74,7 @@ abstract class AbstractVisitorGenerator(val referencesData: DataCollector.Refere
|
|||||||
printWithNoIndent(")")
|
printWithNoIndent(")")
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fun Printer.separatedOneLine(iterable: Iterable<Any>, separator: Any) {
|
private fun Printer.separatedOneLine(iterable: Iterable<Any>, separator: Any) {
|
||||||
var first = true
|
var first = true
|
||||||
for (element in iterable) {
|
for (element in iterable) {
|
||||||
if (!first) {
|
if (!first) {
|
||||||
@@ -86,7 +86,7 @@ abstract class AbstractVisitorGenerator(val referencesData: DataCollector.Refere
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fun Printer.generateDefaultImports() {
|
private fun Printer.generateDefaultImports() {
|
||||||
referencesData.usedPackages.forEach {
|
referencesData.usedPackages.forEach {
|
||||||
println("import ", it.asString(), ".*")
|
println("import ", it.asString(), ".*")
|
||||||
}
|
}
|
||||||
@@ -118,8 +118,8 @@ abstract class AbstractVisitorGenerator(val referencesData: DataCollector.Refere
|
|||||||
|
|
||||||
|
|
||||||
fun allElementTypes() =
|
fun allElementTypes() =
|
||||||
referencesData.back.let {
|
referencesData.back.let { map ->
|
||||||
it.keys + it.values.flatten()
|
map.keys + map.values.flatten()
|
||||||
}.distinct()
|
}.distinct()
|
||||||
|
|
||||||
abstract fun Printer.generateContent()
|
abstract fun Printer.generateContent()
|
||||||
|
|||||||
@@ -11,9 +11,28 @@ import org.jetbrains.kotlin.psi.psiUtil.findDescendantOfType
|
|||||||
|
|
||||||
class DataCollector {
|
class DataCollector {
|
||||||
|
|
||||||
private val references = mutableMapOf<String, List<String>>()
|
data class NameWithTypeParameters(val name: String, val typeParameters: List<String>) : Comparable<NameWithTypeParameters> {
|
||||||
private val packagePerClass = mutableMapOf<String, FqName>()
|
override fun compareTo(other: NameWithTypeParameters): Int = name.compareTo(other.name)
|
||||||
private val baseTransformedTypes = mutableListOf<String>()
|
|
||||||
|
constructor(name: String, typeParameterString: String) :
|
||||||
|
this(name, typeParameterString.drop(1).dropLast(1).split(" ", "\t", ",").filter { it.isNotEmpty() })
|
||||||
|
|
||||||
|
constructor(name: String) : this(name, emptyList())
|
||||||
|
|
||||||
|
override fun toString(): String =
|
||||||
|
name + if (typeParameters.isEmpty()) "" else typeParameters.joinToString(prefix = "<", postfix = ">", separator = ", ")
|
||||||
|
}
|
||||||
|
|
||||||
|
private val references = mutableMapOf<NameWithTypeParameters, List<NameWithTypeParameters>>()
|
||||||
|
private val packagePerClass = mutableMapOf<NameWithTypeParameters, FqName>()
|
||||||
|
private val baseTransformedTypes = mutableListOf<NameWithTypeParameters>()
|
||||||
|
|
||||||
|
private fun KtSuperTypeListEntry.toNameWithTypeParameters(): NameWithTypeParameters? {
|
||||||
|
val type = typeAsUserType ?: return null
|
||||||
|
val name = type.referencedName ?: return null
|
||||||
|
val typeArguments = type.typeArgumentList?.text ?: ""
|
||||||
|
return NameWithTypeParameters(name, typeArguments)
|
||||||
|
}
|
||||||
|
|
||||||
fun readFile(file: KtFile) {
|
fun readFile(file: KtFile) {
|
||||||
file.acceptChildren(object : KtVisitorVoid() {
|
file.acceptChildren(object : KtVisitorVoid() {
|
||||||
@@ -24,14 +43,18 @@ class DataCollector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun visitClass(klass: KtClass) {
|
override fun visitClass(klass: KtClass) {
|
||||||
val className = klass.name
|
val className = klass.name ?: run {
|
||||||
if (klass.isInterface() && className != null) {
|
super.visitClass(klass)
|
||||||
packagePerClass[className] = file.packageFqName
|
return
|
||||||
|
}
|
||||||
|
val classNameWithParameters = NameWithTypeParameters(className, klass.typeParameterList?.text ?: "")
|
||||||
|
if (klass.isInterface()) {
|
||||||
|
packagePerClass[classNameWithParameters] = file.packageFqName
|
||||||
val isBaseTT = klass.annotationEntries.any {
|
val isBaseTT = klass.annotationEntries.any {
|
||||||
it.shortName?.asString() == BASE_TRANSFORMED_TYPE_ANNOTATION_NAME
|
it.shortName?.asString() == BASE_TRANSFORMED_TYPE_ANNOTATION_NAME
|
||||||
}
|
}
|
||||||
if (isBaseTT) {
|
if (isBaseTT) {
|
||||||
baseTransformedTypes += className
|
baseTransformedTypes += classNameWithParameters
|
||||||
}
|
}
|
||||||
|
|
||||||
val manual = klass.superTypeListEntries.find {
|
val manual = klass.superTypeListEntries.find {
|
||||||
@@ -40,11 +63,11 @@ class DataCollector {
|
|||||||
} != null
|
} != null
|
||||||
}
|
}
|
||||||
if (manual != null) {
|
if (manual != null) {
|
||||||
references[className] = listOfNotNull(manual.typeAsUserType?.referencedName)
|
references[classNameWithParameters] = listOfNotNull(manual.toNameWithTypeParameters())
|
||||||
} else {
|
} else {
|
||||||
references[className] =
|
references[classNameWithParameters] =
|
||||||
klass.superTypeListEntries.mapNotNull {
|
klass.superTypeListEntries.mapNotNull {
|
||||||
it.typeAsUserType?.referencedName
|
it.toNameWithTypeParameters()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -55,8 +78,8 @@ class DataCollector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun Map<String, List<String>>.computeBackReferences(): Map<String, List<String>> {
|
private fun <K> Map<K, List<K>>.computeBackReferences(): Map<K, List<K>> {
|
||||||
val result = mutableMapOf<String, List<String>>()
|
val result = mutableMapOf<K, List<K>>()
|
||||||
|
|
||||||
this.forEach { (k, v) ->
|
this.forEach { (k, v) ->
|
||||||
v.forEach {
|
v.forEach {
|
||||||
@@ -66,7 +89,7 @@ class DataCollector {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Map<String, List<String>>.sorted(): Map<String, List<String>> {
|
private fun <K : Comparable<K>> Map<K, List<K>>.sortedMap(): Map<K, List<K>> {
|
||||||
return this.toSortedMap().mapValues { (_, v) -> v.sorted() }
|
return this.toSortedMap().mapValues { (_, v) -> v.sorted() }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,17 +103,17 @@ class DataCollector {
|
|||||||
|
|
||||||
val cleanBack = back.filterKeys { it in keysToKeep }
|
val cleanBack = back.filterKeys { it in keysToKeep }
|
||||||
return ReferencesData(
|
return ReferencesData(
|
||||||
cleanBack.computeBackReferences().sorted(),
|
cleanBack.computeBackReferences().sortedMap(),
|
||||||
cleanBack.sorted(),
|
cleanBack.sortedMap(),
|
||||||
packagePerClass.filterKeys { it in keysToKeep }.values.distinct().sortedBy { it.asString() },
|
packagePerClass.filterKeys { it in keysToKeep }.values.distinct().sortedBy { it.asString() },
|
||||||
baseTransformedTypes.sorted()
|
baseTransformedTypes.sorted()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
data class ReferencesData(
|
data class ReferencesData(
|
||||||
val direct: Map<String, List<String>>,
|
val direct: Map<NameWithTypeParameters, List<NameWithTypeParameters>>,
|
||||||
val back: Map<String, List<String>>,
|
val back: Map<NameWithTypeParameters, List<NameWithTypeParameters>>,
|
||||||
val usedPackages: List<FqName>,
|
val usedPackages: List<FqName>,
|
||||||
val baseTransformedTypes: List<String>
|
val baseTransformedTypes: List<NameWithTypeParameters>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.fir.visitors.generator
|
package org.jetbrains.kotlin.fir.visitors.generator
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.fir.visitors.generator.DataCollector.NameWithTypeParameters
|
||||||
import org.jetbrains.kotlin.utils.Printer
|
import org.jetbrains.kotlin.utils.Printer
|
||||||
|
|
||||||
class ParametricTransformerGenerator(data: DataCollector.ReferencesData) : AbstractVisitorGenerator(data) {
|
class ParametricTransformerGenerator(data: DataCollector.ReferencesData) : AbstractVisitorGenerator(data) {
|
||||||
@@ -15,8 +16,8 @@ class ParametricTransformerGenerator(data: DataCollector.ReferencesData) : Abstr
|
|||||||
generateFunction(
|
generateFunction(
|
||||||
"transformElement",
|
"transformElement",
|
||||||
mapOf(
|
mapOf(
|
||||||
"element" to "E",
|
"element" to NameWithTypeParameters("E"),
|
||||||
"data" to "D"
|
"data" to NameWithTypeParameters("D")
|
||||||
),
|
),
|
||||||
constructCompositeBoxType("E"),
|
constructCompositeBoxType("E"),
|
||||||
typeParameters = listOf("E : $FIR_ELEMENT_CLASS_NAME"),
|
typeParameters = listOf("E : $FIR_ELEMENT_CLASS_NAME"),
|
||||||
@@ -40,7 +41,7 @@ class ParametricTransformerGenerator(data: DataCollector.ReferencesData) : Abstr
|
|||||||
return "$TRANSFORMER_RESULT_NAME<$type>"
|
return "$TRANSFORMER_RESULT_NAME<$type>"
|
||||||
}
|
}
|
||||||
|
|
||||||
val baseTypes = mutableMapOf<String, String>().also {
|
val baseTypes = mutableMapOf<NameWithTypeParameters, NameWithTypeParameters>().also {
|
||||||
for (baseTransformedType in referencesData.baseTransformedTypes) {
|
for (baseTransformedType in referencesData.baseTransformedTypes) {
|
||||||
it[baseTransformedType] = baseTransformedType
|
it[baseTransformedType] = baseTransformedType
|
||||||
}
|
}
|
||||||
@@ -50,18 +51,19 @@ class ParametricTransformerGenerator(data: DataCollector.ReferencesData) : Abstr
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Printer.generateTrampolineVisit(className: String) {
|
fun Printer.generateTrampolineVisit(className: NameWithTypeParameters) {
|
||||||
val shortcutName = className.classNameWithoutFir
|
val shortcutName = className.name.classNameWithoutFir
|
||||||
val parameterName = shortcutName.decapitalize().safeName
|
val parameterName = shortcutName.decapitalize().safeName
|
||||||
generateFunction(
|
generateFunction(
|
||||||
name = "visit$shortcutName",
|
name = "visit$shortcutName",
|
||||||
parameters = mapOf(
|
parameters = mapOf(
|
||||||
parameterName to className,
|
parameterName to className,
|
||||||
"data" to "D"
|
"data" to NameWithTypeParameters("D")
|
||||||
),
|
),
|
||||||
returnType = constructCompositeBoxType(FIR_ELEMENT_CLASS_NAME),
|
returnType = constructCompositeBoxType(FIR_ELEMENT_CLASS_NAME.name),
|
||||||
override = true,
|
override = true,
|
||||||
final = true
|
final = true,
|
||||||
|
typeParameters = className.typeParameters
|
||||||
) {
|
) {
|
||||||
print("return ")
|
print("return ")
|
||||||
generateCall("transform$shortcutName", listOf(parameterName, "data"))
|
generateCall("transform$shortcutName", listOf(parameterName, "data"))
|
||||||
@@ -69,23 +71,26 @@ class ParametricTransformerGenerator(data: DataCollector.ReferencesData) : Abstr
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Printer.generateTransformMethod(className: String, parent: String) {
|
fun Printer.generateTransformMethod(
|
||||||
|
className: NameWithTypeParameters,
|
||||||
|
parent: NameWithTypeParameters
|
||||||
|
) {
|
||||||
val baseType = baseTypes[className]
|
val baseType = baseTypes[className]
|
||||||
|
|
||||||
val shortcutName = className.classNameWithoutFir
|
val shortcutName = className.name.classNameWithoutFir
|
||||||
val parameterName = shortcutName.decapitalize().safeName
|
val parameterName = shortcutName.decapitalize().safeName
|
||||||
if (baseType == null) {
|
if (baseType == null) {
|
||||||
generateFunction(
|
generateFunction(
|
||||||
"transform$shortcutName",
|
"transform$shortcutName",
|
||||||
mapOf(
|
mapOf(
|
||||||
parameterName to "E",
|
parameterName to NameWithTypeParameters("E"),
|
||||||
"data" to "D"
|
"data" to NameWithTypeParameters("D")
|
||||||
),
|
),
|
||||||
constructCompositeBoxType("E"),
|
constructCompositeBoxType("E"),
|
||||||
typeParameters = listOf("E : $parent")
|
typeParameters = listOf("E : $parent") + className.typeParameters
|
||||||
) {
|
) {
|
||||||
print("return ")
|
print("return ")
|
||||||
generateCall("transform${parent.classNameWithoutFir}", listOf(parameterName, "data"))
|
generateCall("transform${parent.name.classNameWithoutFir}", listOf(parameterName, "data"))
|
||||||
printlnWithNoIndent()
|
printlnWithNoIndent()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -93,12 +98,13 @@ class ParametricTransformerGenerator(data: DataCollector.ReferencesData) : Abstr
|
|||||||
"transform$shortcutName",
|
"transform$shortcutName",
|
||||||
mapOf(
|
mapOf(
|
||||||
parameterName to className,
|
parameterName to className,
|
||||||
"data" to "D"
|
"data" to NameWithTypeParameters("D")
|
||||||
),
|
),
|
||||||
constructCompositeBoxType(baseType)
|
constructCompositeBoxType(baseType.name),
|
||||||
|
typeParameters = className.typeParameters
|
||||||
) {
|
) {
|
||||||
print("return ")
|
print("return ")
|
||||||
generateCall("transform${parent.classNameWithoutFir}", listOf(parameterName, "data"))
|
generateCall("transform${parent.name.classNameWithoutFir}", listOf(parameterName, "data"))
|
||||||
printlnWithNoIndent()
|
printlnWithNoIndent()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ class SimpleVisitorGenerator(referencesData: DataCollector.ReferencesData) : Abs
|
|||||||
"visitElement",
|
"visitElement",
|
||||||
parameters = mapOf(
|
parameters = mapOf(
|
||||||
"element" to FIR_ELEMENT_CLASS_NAME,
|
"element" to FIR_ELEMENT_CLASS_NAME,
|
||||||
"data" to "D"
|
"data" to DataCollector.NameWithTypeParameters("D")
|
||||||
),
|
),
|
||||||
returnType = "R",
|
returnType = "R",
|
||||||
body = null
|
body = null
|
||||||
@@ -27,19 +27,23 @@ class SimpleVisitorGenerator(referencesData: DataCollector.ReferencesData) : Abs
|
|||||||
println("}")
|
println("}")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Printer.generateVisit(className: String, parent: String) {
|
private fun Printer.generateVisit(
|
||||||
val shortcutName = className.classNameWithoutFir
|
className: DataCollector.NameWithTypeParameters,
|
||||||
|
parent: DataCollector.NameWithTypeParameters
|
||||||
|
) {
|
||||||
|
val shortcutName = className.name.classNameWithoutFir
|
||||||
val parameterName = shortcutName.decapitalize().safeName
|
val parameterName = shortcutName.decapitalize().safeName
|
||||||
generateFunction(
|
generateFunction(
|
||||||
name = "visit$shortcutName",
|
name = "visit$shortcutName",
|
||||||
parameters = mapOf(
|
parameters = mapOf(
|
||||||
parameterName to className,
|
parameterName to className,
|
||||||
"data" to "D"
|
"data" to DataCollector.NameWithTypeParameters("D")
|
||||||
),
|
),
|
||||||
returnType = "R"
|
returnType = "R",
|
||||||
|
typeParameters = className.typeParameters
|
||||||
) {
|
) {
|
||||||
print("return ")
|
print("return ")
|
||||||
generateCall("visit${parent.classNameWithoutFir}", listOf(parameterName, "data"))
|
generateCall("visit${parent.name.classNameWithoutFir}", listOf(parameterName, "data"))
|
||||||
println()
|
println()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.fir.visitors.generator
|
package org.jetbrains.kotlin.fir.visitors.generator
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.fir.visitors.generator.DataCollector.NameWithTypeParameters
|
||||||
import org.jetbrains.kotlin.utils.Printer
|
import org.jetbrains.kotlin.utils.Printer
|
||||||
|
|
||||||
class UnitVisitorGenerator(referencesData: DataCollector.ReferencesData) : AbstractVisitorGenerator(referencesData) {
|
class UnitVisitorGenerator(referencesData: DataCollector.ReferencesData) : AbstractVisitorGenerator(referencesData) {
|
||||||
@@ -33,34 +34,39 @@ class UnitVisitorGenerator(referencesData: DataCollector.ReferencesData) : Abstr
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun Printer.generateVisit(className: String, parent: String) {
|
private fun Printer.generateVisit(
|
||||||
val shortcutName = className.classNameWithoutFir
|
className: NameWithTypeParameters,
|
||||||
|
parent: NameWithTypeParameters
|
||||||
|
) {
|
||||||
|
val shortcutName = className.name.classNameWithoutFir
|
||||||
val parameterName = shortcutName.decapitalize().safeName
|
val parameterName = shortcutName.decapitalize().safeName
|
||||||
generateFunction(
|
generateFunction(
|
||||||
name = "visit$shortcutName",
|
name = "visit$shortcutName",
|
||||||
parameters = mapOf(
|
parameters = mapOf(
|
||||||
parameterName to className
|
parameterName to className
|
||||||
),
|
),
|
||||||
returnType = "Unit"
|
returnType = "Unit",
|
||||||
|
typeParameters = className.typeParameters
|
||||||
) {
|
) {
|
||||||
printIndent()
|
printIndent()
|
||||||
generateCall("visit${parent.classNameWithoutFir}", listOf(parameterName, "null"))
|
generateCall("visit${parent.name.classNameWithoutFir}", listOf(parameterName, "null"))
|
||||||
println()
|
println()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Printer.generateTrampolineVisit(className: String) {
|
private fun Printer.generateTrampolineVisit(className: NameWithTypeParameters) {
|
||||||
val shortcutName = className.classNameWithoutFir
|
val shortcutName = className.name.classNameWithoutFir
|
||||||
val parameterName = shortcutName.decapitalize().safeName
|
val parameterName = shortcutName.decapitalize().safeName
|
||||||
generateFunction(
|
generateFunction(
|
||||||
name = "visit$shortcutName",
|
name = "visit$shortcutName",
|
||||||
parameters = mapOf(
|
parameters = mapOf(
|
||||||
parameterName to className,
|
parameterName to className,
|
||||||
"data" to "Nothing?"
|
"data" to NameWithTypeParameters("Nothing?")
|
||||||
),
|
),
|
||||||
returnType = "Unit",
|
returnType = "Unit",
|
||||||
override = true,
|
override = true,
|
||||||
final = true
|
final = true,
|
||||||
|
typeParameters = className.typeParameters
|
||||||
) {
|
) {
|
||||||
printIndent()
|
printIndent()
|
||||||
generateCall("visit$shortcutName", listOf(parameterName))
|
generateCall("visit$shortcutName", listOf(parameterName))
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import org.jetbrains.kotlin.psi.KtFile
|
|||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
|
|
||||||
const val FIR_ELEMENT_CLASS_NAME = "FirElement"
|
val FIR_ELEMENT_CLASS_NAME = DataCollector.NameWithTypeParameters("FirElement")
|
||||||
const val VISITOR_PACKAGE = "org.jetbrains.kotlin.fir.visitors"
|
const val VISITOR_PACKAGE = "org.jetbrains.kotlin.fir.visitors"
|
||||||
const val SIMPLE_VISITOR_NAME = "FirVisitor"
|
const val SIMPLE_VISITOR_NAME = "FirVisitor"
|
||||||
const val UNIT_VISITOR_NAME = "FirVisitorVoid"
|
const val UNIT_VISITOR_NAME = "FirVisitorVoid"
|
||||||
@@ -71,7 +71,10 @@ fun AbstractVisitorGenerator.runGenerator(file: File) {
|
|||||||
val String.classNameWithoutFir get() = this.removePrefix("Fir")
|
val String.classNameWithoutFir get() = this.removePrefix("Fir")
|
||||||
|
|
||||||
|
|
||||||
fun DataCollector.ReferencesData.walkHierarchyTopDown(from: String, l: (p: String, e: String) -> Unit) {
|
fun DataCollector.ReferencesData.walkHierarchyTopDown(
|
||||||
|
from: DataCollector.NameWithTypeParameters,
|
||||||
|
l: (p: DataCollector.NameWithTypeParameters, e: DataCollector.NameWithTypeParameters) -> Unit
|
||||||
|
) {
|
||||||
val referents = back[from] ?: return
|
val referents = back[from] ?: return
|
||||||
for (referent in referents) {
|
for (referent in referents) {
|
||||||
l(from, referent)
|
l(from, referent)
|
||||||
|
|||||||
+8
@@ -138,6 +138,10 @@ abstract class FirTransformer<in D> : FirVisitor<CompositeTransformResult<FirEle
|
|||||||
return transformCall(delegatedConstructorCall, data)
|
return transformCall(delegatedConstructorCall, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
open fun <T> transformConstExpression(constExpression: FirConstExpression<T>, data: D): CompositeTransformResult<FirStatement> {
|
||||||
|
return transformExpression(constExpression, data)
|
||||||
|
}
|
||||||
|
|
||||||
open fun transformErrorExpression(errorExpression: FirErrorExpression, data: D): CompositeTransformResult<FirStatement> {
|
open fun transformErrorExpression(errorExpression: FirErrorExpression, data: D): CompositeTransformResult<FirStatement> {
|
||||||
return transformExpression(errorExpression, data)
|
return transformExpression(errorExpression, data)
|
||||||
}
|
}
|
||||||
@@ -310,6 +314,10 @@ abstract class FirTransformer<in D> : FirVisitor<CompositeTransformResult<FirEle
|
|||||||
return transformBody(body, data)
|
return transformBody(body, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final override fun <T> visitConstExpression(constExpression: FirConstExpression<T>, data: D): CompositeTransformResult<FirElement> {
|
||||||
|
return transformConstExpression(constExpression, data)
|
||||||
|
}
|
||||||
|
|
||||||
final override fun visitErrorExpression(errorExpression: FirErrorExpression, data: D): CompositeTransformResult<FirElement> {
|
final override fun visitErrorExpression(errorExpression: FirErrorExpression, data: D): CompositeTransformResult<FirElement> {
|
||||||
return transformErrorExpression(errorExpression, data)
|
return transformErrorExpression(errorExpression, data)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -138,6 +138,10 @@ abstract class FirVisitor<out R, in D> {
|
|||||||
return visitCall(delegatedConstructorCall, data)
|
return visitCall(delegatedConstructorCall, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
open fun <T> visitConstExpression(constExpression: FirConstExpression<T>, data: D): R {
|
||||||
|
return visitExpression(constExpression, data)
|
||||||
|
}
|
||||||
|
|
||||||
open fun visitErrorExpression(errorExpression: FirErrorExpression, data: D): R {
|
open fun visitErrorExpression(errorExpression: FirErrorExpression, data: D): R {
|
||||||
return visitExpression(errorExpression, data)
|
return visitExpression(errorExpression, data)
|
||||||
}
|
}
|
||||||
|
|||||||
+8
@@ -138,6 +138,10 @@ abstract class FirVisitorVoid : FirVisitor<Unit, Nothing?>() {
|
|||||||
visitCall(delegatedConstructorCall, null)
|
visitCall(delegatedConstructorCall, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
open fun <T> visitConstExpression(constExpression: FirConstExpression<T>) {
|
||||||
|
visitExpression(constExpression, null)
|
||||||
|
}
|
||||||
|
|
||||||
open fun visitErrorExpression(errorExpression: FirErrorExpression) {
|
open fun visitErrorExpression(errorExpression: FirErrorExpression) {
|
||||||
visitExpression(errorExpression, null)
|
visitExpression(errorExpression, null)
|
||||||
}
|
}
|
||||||
@@ -310,6 +314,10 @@ abstract class FirVisitorVoid : FirVisitor<Unit, Nothing?>() {
|
|||||||
visitBody(body)
|
visitBody(body)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final override fun <T> visitConstExpression(constExpression: FirConstExpression<T>, data: Nothing?) {
|
||||||
|
visitConstExpression(constExpression)
|
||||||
|
}
|
||||||
|
|
||||||
final override fun visitErrorExpression(errorExpression: FirErrorExpression, data: Nothing?) {
|
final override fun visitErrorExpression(errorExpression: FirErrorExpression, data: Nothing?) {
|
||||||
visitErrorExpression(errorExpression)
|
visitErrorExpression(errorExpression)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user