Raw FIR: implement expression trees & conversions from PSI

Testing: total kotlin test controls no stubs in FIR in non-stub-mode
#KT-29002 Fixed
This commit is contained in:
Mikhail Glukhikh
2019-01-15 09:47:29 +03:00
parent aa97175d40
commit db2fb86c8e
214 changed files with 5754 additions and 517 deletions
@@ -0,0 +1,375 @@
/*
* Copyright 2010-2019 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.builder
import com.intellij.psi.PsiElement
import com.intellij.psi.tree.IElementType
import org.jetbrains.kotlin.KtNodeTypes
import org.jetbrains.kotlin.fir.FirReference
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirNamedDeclaration
import org.jetbrains.kotlin.fir.declarations.impl.FirVariableImpl
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.expressions.impl.*
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
import org.jetbrains.kotlin.fir.references.FirExplicitThisReference
import org.jetbrains.kotlin.fir.references.FirSimpleNamedReference
import org.jetbrains.kotlin.fir.types.FirType
import org.jetbrains.kotlin.fir.types.impl.FirImplicitTypeImpl
import org.jetbrains.kotlin.ir.expressions.IrConstKind
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.constants.evaluate.*
import org.jetbrains.kotlin.types.expressions.OperatorConventions
internal fun String.parseCharacter(): Char? {
// 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)
}
}
internal 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
}
internal fun translateEscape(c: Char): Char? =
when (c) {
't' -> '\t'
'b' -> '\b'
'n' -> '\n'
'r' -> '\r'
'\'' -> '\''
'\"' -> '\"'
'\\' -> '\\'
'$' -> '$'
else -> null
}
internal fun generateConstantExpressionByLiteral(session: FirSession, expression: KtConstantExpression): FirExpression {
val type = expression.node.elementType
val text: String = expression.text
val convertedText: Any? = when (type) {
KtNodeTypes.INTEGER_CONSTANT, KtNodeTypes.FLOAT_CONSTANT -> parseNumericLiteral(text, type)
KtNodeTypes.BOOLEAN_CONSTANT -> parseBoolean(text)
else -> null
}
return when (type) {
KtNodeTypes.INTEGER_CONSTANT ->
if (convertedText is Long &&
(hasLongSuffix(text) || hasUnsignedLongSuffix(text) || hasUnsignedSuffix(text) ||
convertedText > Int.MAX_VALUE || convertedText < Int.MIN_VALUE)
) {
FirConstExpressionImpl(
session, expression, IrConstKind.Long, convertedText, "Incorrect long: $text"
)
} else {
// TODO: support byte / short
FirConstExpressionImpl(session, expression, IrConstKind.Int, (convertedText as Number).toInt(), "Incorrect int: $text")
}
KtNodeTypes.FLOAT_CONSTANT ->
if (convertedText is Float) {
FirConstExpressionImpl(
session, expression, IrConstKind.Float, convertedText, "Incorrect float: $text"
)
} else {
FirConstExpressionImpl(
session, expression, IrConstKind.Double, convertedText as Double, "Incorrect double: $text"
)
}
KtNodeTypes.CHARACTER_CONSTANT ->
FirConstExpressionImpl(
session, expression, IrConstKind.Char, text.parseCharacter(), "Incorrect character: $text"
)
KtNodeTypes.BOOLEAN_CONSTANT ->
FirConstExpressionImpl(session, expression, IrConstKind.Boolean, convertedText as Boolean)
KtNodeTypes.NULL ->
FirConstExpressionImpl(session, expression, IrConstKind.Null, null)
else ->
throw AssertionError("Unknown literal type: $type, $text")
}
}
internal fun IElementType.toBinaryName(): Name? {
return OperatorConventions.BINARY_OPERATION_NAMES[this]
}
internal fun IElementType.toUnaryName(): Name? {
return OperatorConventions.UNARY_OPERATION_NAMES[this]
}
internal fun IElementType.toFirOperation(): FirOperation =
when (this) {
KtTokens.LT -> FirOperation.LT
KtTokens.GT -> FirOperation.GT
KtTokens.LTEQ -> FirOperation.LT_EQ
KtTokens.GTEQ -> FirOperation.GT_EQ
KtTokens.EQEQ -> FirOperation.EQ
KtTokens.EXCLEQ -> FirOperation.NOT_EQ
KtTokens.EQEQEQ -> FirOperation.IDENTITY
KtTokens.EXCLEQEQEQ -> FirOperation.NOT_IDENTITY
KtTokens.ANDAND -> FirOperation.AND
KtTokens.OROR -> FirOperation.OR
KtTokens.IN_KEYWORD -> FirOperation.IN
KtTokens.NOT_IN -> FirOperation.NOT_IN
KtTokens.RANGE -> FirOperation.RANGE
KtTokens.EQ -> FirOperation.ASSIGN
KtTokens.PLUSEQ -> FirOperation.PLUS_ASSIGN
KtTokens.MINUSEQ -> FirOperation.MINUS_ASSIGN
KtTokens.MULTEQ -> FirOperation.TIMES_ASSIGN
KtTokens.DIVEQ -> FirOperation.DIV_ASSIGN
KtTokens.PERCEQ -> FirOperation.REM_ASSIGN
KtTokens.AS_KEYWORD -> FirOperation.AS
KtTokens.AS_SAFE -> FirOperation.SAFE_AS
else -> throw AssertionError(this.toString())
}
internal fun FirExpression.generateNotNullOrOther(other: FirExpression, caseId: String, basePsi: KtElement): FirWhenExpression {
val subjectName = Name.special("<$caseId>")
val subjectVariable = generateTemporaryVariable(session, psi, subjectName, this)
val subjectExpression = FirWhenSubjectExpression(session, psi)
return FirWhenExpressionImpl(
session, basePsi, this, subjectVariable
).apply {
branches += FirWhenBranchImpl(
session, psi,
FirOperatorCallImpl(session, psi, FirOperation.NOT_EQ).apply {
arguments += subjectExpression
arguments += FirConstExpressionImpl(session, psi, IrConstKind.Null, null)
},
FirSingleExpressionBlock(
session,
generateAccessExpression(session, psi, subjectName)
)
)
branches += FirWhenBranchImpl(
session, other.psi, FirElseIfTrueCondition(session, psi),
FirSingleExpressionBlock(session, other)
)
}
}
internal fun generateIncrementOrDecrementBlock(
session: FirSession,
baseExpression: KtUnaryExpression,
argument: KtExpression?,
callName: Name,
prefix: Boolean,
convert: KtExpression.() -> FirExpression
): FirExpression {
if (argument == null) {
return FirErrorExpressionImpl(session, argument, "Inc/dec without operand")
}
return FirBlockImpl(session, baseExpression).apply {
val tempName = Name.special("<unary>")
statements += generateTemporaryVariable(session, baseExpression, tempName, argument.convert())
val resultName = Name.special("<unary-result>")
val resultInitializer = FirFunctionCallImpl(session, baseExpression).apply {
this.calleeReference = FirSimpleNamedReference(session, baseExpression.operationReference, callName)
this.arguments += generateAccessExpression(session, baseExpression, tempName)
}
val resultVar = generateTemporaryVariable(session, baseExpression, resultName, resultInitializer)
val assignment = argument.generateAssignment(
session, baseExpression,
if (prefix && argument !is KtSimpleNameExpression)
generateAccessExpression(session, baseExpression, resultName)
else
resultInitializer,
FirOperation.ASSIGN, convert
)
fun appendAssignment() {
if (assignment is FirBlock) {
statements += assignment.statements
} else {
statements += assignment
}
}
if (prefix) {
if (argument !is KtSimpleNameExpression) {
statements += resultVar
appendAssignment()
statements += generateAccessExpression(session, baseExpression, resultName)
} else {
appendAssignment()
statements += generateAccessExpression(session, baseExpression, argument.getReferencedNameAsName())
}
} else {
appendAssignment()
statements += generateAccessExpression(session, baseExpression, tempName)
}
}
}
internal fun generateAccessExpression(session: FirSession, psi: PsiElement?, name: Name): FirAccessExpression =
FirAccessExpressionImpl(session, psi).apply {
calleeReference = FirSimpleNamedReference(session, psi, name)
}
internal fun generateDestructuringBlock(
session: FirSession,
multiDeclaration: KtDestructuringDeclaration,
container: FirNamedDeclaration,
extractAnnotationsTo: KtAnnotated.(FirAbstractAnnotatedElement) -> Unit,
toFirOrImplicitType: KtTypeReference?.() -> FirType
): FirExpression {
return FirBlockImpl(session, multiDeclaration).apply {
if (container is FirVariable) {
statements += container
}
val isVar = multiDeclaration.isVar
for ((index, entry) in multiDeclaration.entries.withIndex()) {
statements += FirVariableImpl(
session, entry, entry.nameAsSafeName,
entry.typeReference.toFirOrImplicitType(), isVar,
FirComponentCallImpl(session, entry, index + 1).apply {
arguments += generateAccessExpression(session, entry, container.name)
}
).apply {
entry.extractAnnotationsTo(this)
}
}
}
}
internal fun generateTemporaryVariable(
session: FirSession, psi: PsiElement?, name: Name, initializer: FirExpression
): FirVariable = FirVariableImpl(session, psi, name, FirImplicitTypeImpl(session, psi), false, initializer)
internal fun generateTemporaryVariable(
session: FirSession, psi: PsiElement?, specialName: String, initializer: FirExpression
): FirVariable = generateTemporaryVariable(session, psi, Name.special("<$specialName>"), initializer)
private fun FirModifiableAccess.initializeLValue(
session: FirSession,
left: KtExpression?,
convertQualified: KtQualifiedExpression.() -> FirAccess?
): FirReference {
return when (left) {
is KtSimpleNameExpression -> {
FirSimpleNamedReference(session, left, left.getReferencedNameAsName())
}
is KtThisExpression -> {
FirExplicitThisReference(session, left, left.getLabelName())
}
is KtQualifiedExpression -> {
val firMemberAccess = left.convertQualified()
if (firMemberAccess != null) {
explicitReceiver = firMemberAccess.explicitReceiver
safe = firMemberAccess.safe
firMemberAccess.calleeReference
} else {
FirErrorNamedReference(session, left, "Unsupported qualified LValue: ${left.text}")
}
}
is KtParenthesizedExpression -> {
initializeLValue(session, left.expression, convertQualified)
}
else -> {
FirErrorNamedReference(session, left, "Unsupported LValue: ${left?.javaClass}")
}
}
}
internal fun KtExpression?.generateAssignment(
session: FirSession,
psi: PsiElement?,
value: FirExpression,
operation: FirOperation,
convert: KtExpression.() -> FirExpression
): FirStatement {
if (this is KtParenthesizedExpression) {
return expression.generateAssignment(session, psi, value, operation, convert)
}
if (this is KtArrayAccessExpression) {
val arrayExpression = this.arrayExpression
val arraySet = FirArraySetCallImpl(session, psi, value, operation).apply {
for (indexExpression in indexExpressions) {
arguments += indexExpression.convert()
}
}
if (arrayExpression is KtSimpleNameExpression) {
return arraySet.apply {
calleeReference = initializeLValue(session, arrayExpression) { convert() as? FirAccess }
}
}
return FirBlockImpl(session, arrayExpression).apply {
val name = Name.special("<array-set>")
statements += generateTemporaryVariable(
session, this@generateAssignment, name,
arrayExpression?.convert() ?: FirErrorExpressionImpl(session, arrayExpression, "No array expression")
)
statements += arraySet.apply { calleeReference = FirSimpleNamedReference(session, arrayExpression, name) }
}
}
if (operation != FirOperation.ASSIGN &&
this !is KtSimpleNameExpression && this !is KtThisExpression &&
(this !is KtQualifiedExpression || selectorExpression !is KtSimpleNameExpression)
) {
return FirBlockImpl(session, this).apply {
val name = Name.special("<complex-set>")
statements += generateTemporaryVariable(
session, this@generateAssignment, name,
this@generateAssignment?.convert() ?: FirErrorExpressionImpl(session, this@generateAssignment, "No LValue in assignment")
)
statements += FirPropertyAssignmentImpl(session, psi, value, operation).apply {
calleeReference = FirSimpleNamedReference(session, this@generateAssignment, name)
}
}
}
return FirPropertyAssignmentImpl(session, psi, value, operation).apply {
calleeReference = initializeLValue(session, this@generateAssignment) { convert() as? FirAccess }
}
}
File diff suppressed because it is too large Load Diff
@@ -7,9 +7,9 @@ FILE: derivedClass.kt
}
<T : Any> public? final? class Derived : Base<T> {
public? constructor(x: T): super<Base<T>>()
public? constructor(x: T): super<Base<T>>(x#)
}
<T : Any> public? final? function create(x: T): Derived<T> {
STUB
return@@@create Derived#(x#)
}
@@ -28,30 +28,33 @@ FILE: enums.kt
internal get(): Double
public? final enum entry MERCURY : Planet {
public? constructor(): super<Planet>()
public? constructor(): super<Planet>(Double(1.0), Double(2.0))
public? open? override function sayHello(): kotlin.Unit {
println#(String(Hello!!!))
}
}
public? final enum entry VENERA : Planet {
public? constructor(): super<Planet>()
public? constructor(): super<Planet>(Double(3.0), Double(4.0))
public? open? override function sayHello(): kotlin.Unit {
println#(String(Ola!!!))
}
}
public? final enum entry EARTH : Planet {
public? constructor(): super<Planet>()
public? constructor(): super<Planet>(Double(5.0), Double(6.0))
public? open? override function sayHello(): kotlin.Unit {
println#(String(Privet!!!))
}
}
public? final? property g(val): Double = STUB
public? final? property g(val): Double = div#(times#(G#, m#), times#(r#, r#))
public? get(): Double
public? abstract function sayHello(): kotlin.Unit
@@ -59,7 +62,7 @@ FILE: enums.kt
public? final? companion object Companion {
public? constructor(): super<kotlin.Any>()
public? final? const property G(val): <implicit> = STUB
public? final? const property G(val): <implicit> = Double(6.67E-11)
public? get(): <implicit>
}
@@ -16,19 +16,19 @@ FILE: enums2.kt
public? get(): Some
public? final enum entry FIRST : SomeEnum {
public? constructor(): super<SomeEnum>()
public? constructor(): super<SomeEnum>(O1#)
public? open? override function check(y: Some): Boolean {
STUB
return@@@check Boolean(true)
}
}
public? final enum entry SECOND : SomeEnum {
public? constructor(): super<SomeEnum>()
public? constructor(): super<SomeEnum>(O2#)
public? open? override function check(y: Some): Boolean {
STUB
return@@@check ==(y#, O2#)
}
}
@@ -11,7 +11,7 @@ FILE: expectActual.kt
}
public? final? actual function foo(): <implicit> {
STUB
return@@@foo String(Hello)
}
public? final? actual property x(val): <implicit> = STUB
public? final? actual property x(val): <implicit> = Int(42)
public? get(): <implicit>
@@ -1,9 +1,9 @@
FILE: functionTypes.kt
<T> public? final? function simpleRun(f: ( (T) -> Unit )): Unit {
STUB
return@@@simpleRun f#()
}
<T, R> public? final? function simpleMap List<T>.(f: ( (T) -> R )): R {
}
<T> public? final? function simpleWith(t: T, f: ( T.() -> Unit )): Unit {
STUB
return@@@simpleWith t#.f#()
}
@@ -2,7 +2,7 @@ FILE: genericFunctions.kt
public? final? interface Any {
}
<reified T : Any> public? final? inline function safeAs Any.(): T? {
STUB
return@@@safeAs as?/T(this#)
}
public? abstract class Summator {
public? constructor(): super<kotlin.Any>()
@@ -10,12 +10,12 @@ FILE: nestedClass.kt
public? constructor(): super<kotlin.Any>()
public? final? class Derived : Base {
public? constructor(s: String): super<Base>()
public? constructor(s: String): super<Base>(s#)
}
public? final? object Obj : Base {
public? constructor(): super<Base>()
public? constructor(): super<Base>(String())
}
@@ -4,8 +4,9 @@ FILE: noPrimaryConstructor.kt
public? get(): String
public? constructor(x: String): super<kotlin.Any>() {
this#.x# = x#
}
public? constructor(): this<NoPrimary>()
public? constructor(): this<NoPrimary>(String())
}
@@ -9,15 +9,16 @@ FILE: simpleClass.kt
public? final? class SomeClass : SomeInterface {
public? constructor(): super<kotlin.Any>()
private final? property baz(val): <implicit> = STUB
private final? property baz(val): <implicit> = Int(42)
private get(): <implicit>
public? open? override function foo(x: Int, y: String): String {
return@@@foo plus#(plus#(y#, x#), baz#)
}
public? open? override property bar(var): Boolean
public? get(): Boolean {
STUB
return Boolean(true)
}
public? set(value: Boolean): kotlin.Unit {
}
@@ -15,11 +15,11 @@ FILE: typeParameters.kt
public? constructor(): super<AbstractList<Int>>()
public? open? override function get(index: Int): Int {
STUB
return@@@get Int(42)
}
public? open? override function concat(other: List<Int>): List<Int> {
STUB
return@@@concat this#
}
}
@@ -0,0 +1,6 @@
interface A
interface B
class C<T> where T : A, T : B {
}
@@ -0,0 +1,9 @@
FILE: where.kt
public? final? interface A {
}
public? final? interface B {
}
<T : A, B> public? final? class C {
public? constructor(): super<kotlin.Any>()
}
@@ -0,0 +1,19 @@
@Target(AnnotationTarget.EXPRESSION)
@Retention(AnnotationRetention.SOURCE)
annotation class Ann
fun foo(arg: Int): Int {
if (@Ann arg == 0) {
@Ann return 1
}
@Ann if (arg == 1) {
return (@Ann 1)
}
return 42
}
data class Two(x: Int, y: Int)
fun bar(two: Two) {
val (@Ann x, @Ann y) = two
}
@@ -0,0 +1,33 @@
FILE: annotated.kt
@Target(AnnotationTarget#.EXPRESSION#) @Retention(AnnotationRetention#.SOURCE#) public? final? annotation class Ann {
public? constructor(): super<kotlin.Any>()
}
public? final? function foo(arg: Int): Int {
when () {
==(@Ann() arg#, Int(0)) -> {
@Ann() return@@@foo Int(1)
}
else -> {
}
}
@Ann() when () {
==(arg#, Int(1)) -> {
return@@@foo @Ann() Int(1)
}
else -> {
}
}
return@@@foo Int(42)
}
public? final? data class Two {
public? constructor(x: Int, y: Int): super<kotlin.Any>()
}
public? final? function bar(two: Two): kotlin.Unit {
val <destruct>: <implicit> = two#
@Ann() val x: <implicit> = component1(<destruct>#)
@Ann() val y: <implicit> = component2(<destruct>#)
}
@@ -0,0 +1,6 @@
val p = 0
fun foo() = 1
class Wrapper(val v: IntArray)
fun test(a: IntArray, w: Wrapper) = a[0] + a[p] + a[foo()] + w.v[0]
@@ -0,0 +1,16 @@
FILE: arrayAccess.kt
public? final? property p(val): <implicit> = Int(0)
public? get(): <implicit>
public? final? function foo(): <implicit> {
return@@@foo Int(1)
}
public? final? class Wrapper {
public? constructor(v: IntArray): super<kotlin.Any>()
public? final? property v(val): IntArray
public? get(): IntArray
}
public? final? function test(a: IntArray, w: Wrapper): <implicit> {
return@@@test plus#(plus#(plus#(a#[Int(0)], a#[p#]), a#[foo#()]), w#.v#[Int(0)])
}
@@ -0,0 +1,10 @@
fun test() {
val x = intArrayOf(1, 2, 3)
x[1] = 0
}
fun foo() = 1
fun test2() {
intArrayOf(1, 2, 3)[foo()] = 1
}
@@ -0,0 +1,12 @@
FILE: arrayAssignment.kt
public? final? function test(): kotlin.Unit {
val x: <implicit> = intArrayOf#(Int(1), Int(2), Int(3))
x#[Int(1)] = Int(0)
}
public? final? function foo(): <implicit> {
return@@@foo Int(1)
}
public? final? function test2(): kotlin.Unit {
val <array-set>: <implicit> = intArrayOf#(Int(1), Int(2), Int(3))
<array-set>#[foo#()] = Int(1)
}
@@ -0,0 +1,33 @@
fun foo(a: Int, b: Int) = if (a > b) a else b
fun bar(a: Double, b: Double): Double {
if (a > b) {
println(a)
return a
} else {
println(b)
return b
}
}
fun baz(a: Long, b: Long): Long {
when {
a > b -> {
println(a)
return a
}
else -> return b
}
}
fun grade(g: Int): String {
return when (g) {
6, 7 -> "Outstanding"
5 -> "Excellent"
4 -> "Good"
3 -> "Mediocre"
in 1..2 -> "Fail"
is Number -> "Number"
else -> "Unknown"
}
}
@@ -0,0 +1,63 @@
FILE: branches.kt
public? final? function foo(a: Int, b: Int): <implicit> {
return@@@foo when () {
>(a#, b#) -> {
a#
}
else -> {
b#
}
}
}
public? final? function bar(a: Double, b: Double): Double {
when () {
>(a#, b#) -> {
println#(a#)
return@@@bar a#
}
else -> {
println#(b#)
return@@@bar b#
}
}
}
public? final? function baz(a: Long, b: Long): Long {
when () {
>(a#, b#) -> {
println#(a#)
return@@@baz a#
}
else -> {
return@@@baz b#
}
}
}
public? final? function grade(g: Int): String {
return@@@grade when (g#) {
||(==($subj$, Int(6)), ==($subj$, Int(7))) -> {
String(Outstanding)
}
==($subj$, Int(5)) -> {
String(Excellent)
}
==($subj$, Int(4)) -> {
String(Good)
}
==($subj$, Int(3)) -> {
String(Mediocre)
}
in($subj$, rangeTo#(Int(1), Int(2))) -> {
String(Fail)
}
is/Number($subj$) -> {
String(Number)
}
else -> {
String(Unknown)
}
}
}
@@ -0,0 +1,22 @@
class A {
fun foo() {}
val bar = 0
}
fun A.qux() {}
fun baz() {}
val test1 = A()::foo
val test2 = A()::bar
val test3 = A()::qux
val test4 = A::foo
val test5 = A::bar
val test6 = A::qux
val test7 = ::baz
@@ -0,0 +1,29 @@
FILE: callableReferences.kt
public? final? class A {
public? constructor(): super<kotlin.Any>()
public? final? function foo(): kotlin.Unit {
}
public? final? property bar(val): <implicit> = Int(0)
public? get(): <implicit>
}
public? final? function qux A.(): kotlin.Unit {
}
public? final? function baz(): kotlin.Unit {
}
public? final? property test1(val): <implicit> = A#()::foo#
public? get(): <implicit>
public? final? property test2(val): <implicit> = A#()::bar#
public? get(): <implicit>
public? final? property test3(val): <implicit> = A#()::qux#
public? get(): <implicit>
public? final? property test4(val): <implicit> = A#::foo#
public? get(): <implicit>
public? final? property test5(val): <implicit> = A#::bar#
public? get(): <implicit>
public? final? property test6(val): <implicit> = A#::qux#
public? get(): <implicit>
public? final? property test7(val): <implicit> = ::baz#
public? get(): <implicit>
@@ -0,0 +1,24 @@
infix fun distance(x: Int, y: Int) = x + y
fun test(): Int = 3 distance 4
fun testRegular(): Int = distance(3, 4)
class My(var x: Int) {
operator fun invoke() = x
fun foo() {}
fun copy() = My(x)
}
fun testInvoke(): Int = My(13)()
fun testQualified(first: My, second: My?) {
println(first.x)
println(second?.x)
first.foo()
second?.foo()
first.copy().foo()
first.x = 42
}
@@ -0,0 +1,40 @@
FILE: calls.kt
public? final? infix function distance(x: Int, y: Int): <implicit> {
return@@@distance plus#(x#, y#)
}
public? final? function test(): Int {
return@@@test distance#(Int(3), Int(4))
}
public? final? function testRegular(): Int {
return@@@testRegular distance#(Int(3), Int(4))
}
public? final? class My {
public? constructor(x: Int): super<kotlin.Any>()
public? final? property x(var): Int
public? get(): Int
public? set(value: Int): kotlin.Unit
public? final? operator function invoke(): <implicit> {
return@@@invoke x#
}
public? final? function foo(): kotlin.Unit {
}
public? final? function copy(): <implicit> {
return@@@copy My#(x#)
}
}
public? final? function testInvoke(): Int {
return@@@testInvoke invoke#(My#(Int(13)))
}
public? final? function testQualified(first: My, second: My?): kotlin.Unit {
println#(first#.x#)
println#(second#?.x#)
first#.foo#()
second#?.foo#()
first#.copy#().foo#()
first#.x# = Int(42)
}
@@ -0,0 +1,14 @@
//WITH_RUNTIME
package test
class A
fun test() {
A::class
test.A::class
A()::class
A::class.java
test.A::class.java
A()::class.java
}
@@ -0,0 +1,13 @@
FILE: classReference.kt
public? final? class A {
public? constructor(): super<kotlin.Any>()
}
public? final? function test(): kotlin.Unit {
<getClass>(A#)
<getClass>(test#.A#)
<getClass>(A#())
<getClass>(A#).java#
<getClass>(test#.A#).java#
<getClass>(A#()).java#
}
@@ -0,0 +1,19 @@
annotation class Ann1(val arr: IntArray)
annotation class Ann2(val arr: DoubleArray)
annotation class Ann3(val arr: Array<String>)
@Ann1([])
@Ann2([])
@Ann3([])
class Zero
@Ann1([1, 2])
class First
@Ann2([3.14])
class Second
@Ann3(["Alpha", "Omega"])
class Third
@@ -0,0 +1,38 @@
FILE: collectionLiterals.kt
public? final? annotation class Ann1 {
public? constructor(arr: IntArray): super<kotlin.Any>()
public? final? property arr(val): IntArray
public? get(): IntArray
}
public? final? annotation class Ann2 {
public? constructor(arr: DoubleArray): super<kotlin.Any>()
public? final? property arr(val): DoubleArray
public? get(): DoubleArray
}
public? final? annotation class Ann3 {
public? constructor(arr: Array<String>): super<kotlin.Any>()
public? final? property arr(val): Array<String>
public? get(): Array<String>
}
@Ann1(<implicitArrayOf>()) @Ann2(<implicitArrayOf>()) @Ann3(<implicitArrayOf>()) public? final? class Zero {
public? constructor(): super<kotlin.Any>()
}
@Ann1(<implicitArrayOf>(Int(1), Int(2))) public? final? class First {
public? constructor(): super<kotlin.Any>()
}
@Ann2(<implicitArrayOf>(Double(3.14))) public? final? class Second {
public? constructor(): super<kotlin.Any>()
}
@Ann3(<implicitArrayOf>(String(Alpha), String(Omega))) public? final? class Third {
public? constructor(): super<kotlin.Any>()
}
@@ -0,0 +1,9 @@
data class Some(val first: Int, val second: Double, val third: String)
fun foo(some: Some) {
var (x, y, z: String) = some
x++
y *= 2.0
z = ""
}
@@ -0,0 +1,25 @@
FILE: destructuring.kt
public? final? data class Some {
public? constructor(first: Int, second: Double, third: String): super<kotlin.Any>()
public? final? property first(val): Int
public? get(): Int
public? final? property second(val): Double
public? get(): Double
public? final? property third(val): String
public? get(): String
}
public? final? function foo(some: Some): kotlin.Unit {
val <destruct>: <implicit> = some#
var x: <implicit> = component1(<destruct>#)
var y: <implicit> = component2(<destruct>#)
var z: String = component3(<destruct>#)
val <unary>: <implicit> = x#
x# = inc#(<unary>#)
<unary>#
y# *= Double(2.0)
z# = String()
}
@@ -0,0 +1,20 @@
fun foo() {
for (i in 1..10) {
println(i)
}
}
fun bar(list: List<String>) {
for (element in list.subList(0, 10)) {
println(element)
}
for (element in list.subList(10, 20)) println(element)
}
data class Some(val x: Int, val y: Int)
fun baz(set: Set<Some>) {
for ((x, y) in set) {
println("x = $x y = $y")
}
}
@@ -0,0 +1,47 @@
FILE: for.kt
public? final? function foo(): kotlin.Unit {
val <range>: <implicit> = rangeTo#(Int(1), Int(10))
val <iterator>: <implicit> = <range>#.iterator#()
while(<iterator>#.hasNext#()) {
val i: <implicit> = <iterator>#.next#()
println#(i#)
}
}
public? final? function bar(list: List<String>): kotlin.Unit {
val <range>: <implicit> = list#.subList#(Int(0), Int(10))
val <iterator>: <implicit> = <range>#.iterator#()
while(<iterator>#.hasNext#()) {
val element: <implicit> = <iterator>#.next#()
println#(element#)
}
val <range>: <implicit> = list#.subList#(Int(10), Int(20))
val <iterator>: <implicit> = <range>#.iterator#()
while(<iterator>#.hasNext#()) {
val element: <implicit> = <iterator>#.next#()
println#(element#)
}
}
public? final? data class Some {
public? constructor(x: Int, y: Int): super<kotlin.Any>()
public? final? property x(val): Int
public? get(): Int
public? final? property y(val): Int
public? get(): Int
}
public? final? function baz(set: Set<Some>): kotlin.Unit {
val <range>: <implicit> = set#
val <iterator>: <implicit> = <range>#.iterator#()
while(<iterator>#.hasNext#()) {
val <destruct>: <implicit> = <iterator>#.next#()
val x: <implicit> = component1(<destruct>#)
val y: <implicit> = component2(<destruct>#)
println#(plus#(String(x = ), x#, String( y = ), y#))
}
}
@@ -0,0 +1,7 @@
fun <T> nullableValue(): T? = null
fun test() {
val n = nullableValue<Int>()
val x = nullableValue<Double>()
val s = nullableValue<String>()
}
@@ -0,0 +1,9 @@
FILE: genericCalls.kt
<T> public? final? function nullableValue(): T? {
return@@@nullableValue Null(null)
}
public? final? function test(): kotlin.Unit {
val n: <implicit> = nullableValue#<Int>()
val x: <implicit> = nullableValue#<Double>()
val s: <implicit> = nullableValue#<String>()
}
@@ -0,0 +1,7 @@
class WithInit(x: Int) {
val x: Int
init {
this.x = x
}
}
@@ -0,0 +1,12 @@
FILE: init.kt
public? final? class WithInit {
public? constructor(x: Int): super<kotlin.Any>()
public? final? property x(val): Int
public? get(): Int
init {
this#.x# = x#
}
}
@@ -0,0 +1,29 @@
data class Tuple(val x: Int, val y: Int)
inline fun use(f: (Tuple) -> Int) = f(Tuple(1, 2))
fun foo(): Int {
val l1 = { t: Tuple ->
val x = t.x
val y = t.y
x + y
}
use { (x, y) -> x + y }
return use {
if (it.x == 0) return@foo 0
return@use it.y
}
}
fun bar(): Int {
return use lambda@{
if (it.x == 0) return@bar 0
return@lambda it.y
}
}
fun test(list: List<Int>) {
val map = mutableMapOf<Int, String>()
list.forEach { map.getOrPut(it, { mutableListOf() }) += "" }
}
@@ -0,0 +1,83 @@
FILE: lambda.kt
public? final? data class Tuple {
public? constructor(x: Int, y: Int): super<kotlin.Any>()
public? final? property x(val): Int
public? get(): Int
public? final? property y(val): Int
public? get(): Int
}
public? final? inline function use(f: ( (Tuple) -> Int )): <implicit> {
return@@@use f#(Tuple#(Int(1), Int(2)))
}
public? final? function foo(): Int {
val l1: <implicit> = function <implicit>.<anonymous>(t: Tuple): <implicit> {
return {
val x: <implicit> = t#.x#
val y: <implicit> = t#.y#
plus#(x#, y#)
}
}
use#(use@function <implicit>.<anonymous>(<destruct>: <implicit>): <implicit> {
return {
val x: <implicit> = component1(<destruct>#)
val y: <implicit> = component2(<destruct>#)
plus#(x#, y#)
}
}
)
return@@@foo use#(use@function <implicit>.<anonymous>(): <implicit> {
return {
when () {
==(it#.x#, Int(0)) -> {
return@@@foo Int(0)
}
else -> {
}
}
return@@@use it#.y#
}
}
)
}
public? final? function bar(): Int {
return@@@bar use#(lambda@function <implicit>.<anonymous>(): <implicit> {
return {
when () {
==(it#.x#, Int(0)) -> {
return@@@bar Int(0)
}
else -> {
}
}
return@@@lambda it#.y#
}
}
)
}
public? final? function test(list: List<Int>): kotlin.Unit {
val map: <implicit> = mutableMapOf#<Int, String>()
list#.forEach#(forEach@function <implicit>.<anonymous>(): <implicit> {
return {
val <complex-set>: <implicit> = map#.getOrPut#(it#, getOrPut@function <implicit>.<anonymous>(): <implicit> {
return {
mutableListOf#()
}
}
)
<complex-set># += String()
}
}
)
}
@@ -0,0 +1,17 @@
fun withLocals(p: Int): Int {
class Local(val pp: Int) {
fun diff() = pp - p
}
val x = Local(42).diff()
fun sum(y: Int, z: Int, f: (Int, Int) -> Int): Int {
return x + f(y + z)
}
val code = (object : Any() {
fun foo() = hashCode()
}).foo()
return sum(code, Local(1).diff(), fun(x: Int, y: Int) = x + y)
}
@@ -0,0 +1,33 @@
FILE: locals.kt
public? final? function withLocals(p: Int): Int {
public? final? class Local {
public? constructor(pp: Int): super<kotlin.Any>()
public? final? property pp(val): Int
public? get(): Int
public? final? function diff(): <implicit> {
return@@@diff minus#(pp#, p#)
}
}
val x: <implicit> = Local#(Int(42)).diff#()
public? final? function sum(y: Int, z: Int, f: ( (Int, Int) -> Int )): Int {
return@@@sum plus#(x#, f#(plus#(y#, z#)))
}
val code: <implicit> = object : Any {
public? constructor(): super<Any>()
public? final? function foo(): <implicit> {
return@@@foo hashCode#()
}
}
.foo#()
return@@@withLocals sum#(code#, Local#(Int(1)).diff#(), function <anonymous>(x: Int, y: Int): <implicit> {
return plus#(x#, y#)
}
)
}
@@ -0,0 +1,16 @@
fun simple() {
var x = 10
x += 20
x -= 5
x /= 5
x *= 10
}
fun List<String>.modify() {
this += "Alpha"
this += "Omega"
}
fun Any.modify() {
(this as List<Int>) += 42
}
@@ -0,0 +1,16 @@
FILE: modifications.kt
public? final? function simple(): kotlin.Unit {
var x: <implicit> = Int(10)
x# += Int(20)
x# -= Int(5)
x# /= Int(5)
x# *= Int(10)
}
public? final? function modify List<String>.(): kotlin.Unit {
this# += String(Alpha)
this# += String(Omega)
}
public? final? function modify Any.(): kotlin.Unit {
val <complex-set>: <implicit> = as/List<Int>(this#)
<complex-set># += Int(42)
}
@@ -0,0 +1,3 @@
fun orFourtyTwo(arg: Int?) = arg ?: 42
fun bang(arg: Int?) = arg!!
@@ -0,0 +1,23 @@
FILE: nullability.kt
public? final? function orFourtyTwo(arg: Int?): <implicit> {
return@@@orFourtyTwo when (val <elvis>: <implicit> = arg#) {
!=($subj$, Null(null)) -> {
<elvis>#
}
else -> {
Int(42)
}
}
}
public? final? function bang(arg: Int?): <implicit> {
return@@@bang when (val <bangbang>: <implicit> = arg#) {
!=($subj$, Null(null)) -> {
<bangbang>#
}
else -> {
throw KotlinNullPointerException#()
}
}
}
@@ -0,0 +1,7 @@
fun foo() {
return
}
fun bar(): String {
return "Hello"
}
@@ -0,0 +1,7 @@
FILE: simpleReturns.kt
public? final? function foo(): kotlin.Unit {
return@@@foo Unit
}
public? final? function bar(): String {
return@@@bar String(Hello)
}
@@ -0,0 +1,19 @@
interface A {
fun foo() {}
}
interface B {
fun foo() {}
fun bar() {}
}
class C : A, B {
override fun bar() {
super.bar()
}
override fun foo() {
super<A>.foo()
super<B>.foo()
}
}
@@ -0,0 +1,27 @@
FILE: super.kt
public? final? interface A {
public? final? function foo(): kotlin.Unit {
}
}
public? final? interface B {
public? final? function foo(): kotlin.Unit {
}
public? final? function bar(): kotlin.Unit {
}
}
public? final? class C : A, B {
public? constructor(): super<kotlin.Any>()
public? open? override function bar(): kotlin.Unit {
super<<implicit>>.bar#()
}
public? open? override function foo(): kotlin.Unit {
super<A>.foo#()
super<B>.foo#()
}
}
@@ -0,0 +1,22 @@
class Some {
fun foo(): Int = 1
fun bar(): Int {
return this.foo()
}
val instance: Some
get() = this@Some
fun String.extension(): Int {
return this@Some.bar() + this.length
}
}
fun Some.extension() = this.bar()
fun test(some: Some): Int {
return with(some) {
this.foo() + this@with.extension()
}
}
@@ -0,0 +1,34 @@
FILE: these.kt
public? final? class Some {
public? constructor(): super<kotlin.Any>()
public? final? function foo(): Int {
return@@@foo Int(1)
}
public? final? function bar(): Int {
return@@@bar this#.foo#()
}
public? final? property instance(val): Some
public? get(): Some {
return this@Some
}
public? final? function extension String.(): Int {
return@@@extension plus#(this@Some.bar#(), this#.length#)
}
}
public? final? function extension Some.(): <implicit> {
return@@@extension this#.bar#()
}
public? final? function test(some: Some): Int {
return@@@test with#(some#, with@function <implicit>.<anonymous>(): <implicit> {
return {
plus#(this#.foo#(), this@with.extension#())
}
}
)
}
@@ -0,0 +1,11 @@
fun some() {
try {
throw KotlinNullPointerException()
} catch (e: RuntimeException) {
println("Runtime exception")
} catch (e: Exception) {
println("Some exception")
} finally {
println("finally")
}
}
@@ -0,0 +1,16 @@
FILE: try.kt
public? final? function some(): kotlin.Unit {
try {
throw KotlinNullPointerException#()
}
catch (e: RuntimeException) {
println#(String(Runtime exception))
}
catch (e: Exception) {
println#(String(Some exception))
}
finally {
println#(String(finally))
}
}
@@ -0,0 +1,6 @@
interface IThing
fun test1(x: Any) = x is IThing
fun test2(x: Any) = x !is IThing
fun test3(x: Any) = x as IThing
fun test4(x: Any) = x as? IThing
@@ -0,0 +1,15 @@
FILE: typeOperators.kt
public? final? interface IThing {
}
public? final? function test1(x: Any): <implicit> {
return@@@test1 is/IThing(x#)
}
public? final? function test2(x: Any): <implicit> {
return@@@test2 !is/IThing(x#)
}
public? final? function test3(x: Any): <implicit> {
return@@@test3 as/IThing(x#)
}
public? final? function test4(x: Any): <implicit> {
return@@@test4 as?/IThing(x#)
}
@@ -0,0 +1,29 @@
fun test() {
var x = 0
val x1 = x++
val x2 = ++x
val x3 = --x
val x4 = x--
if (!(x == 0)) {
println("000")
}
}
class X(val i: Int)
fun test2(x: X) {
val x1 = x.i++
val x2 = ++x.i
}
fun test3(arr: Array<Int>) {
val x1 = arr[0]++
val x2 = ++arr[1]
}
class Y(val arr: Array<Int>)
fun test4(y: Y) {
val x1 = y.arr[0]++
val x2 = ++y.arr[1]
}
@@ -0,0 +1,97 @@
FILE: unary.kt
public? final? function test(): kotlin.Unit {
var x: <implicit> = Int(0)
val x1: <implicit> = {
val <unary>: <implicit> = x#
x# = inc#(<unary>#)
<unary>#
}
val x2: <implicit> = {
val <unary>: <implicit> = x#
x# = inc#(<unary>#)
x#
}
val x3: <implicit> = {
val <unary>: <implicit> = x#
x# = dec#(<unary>#)
x#
}
val x4: <implicit> = {
val <unary>: <implicit> = x#
x# = dec#(<unary>#)
<unary>#
}
when () {
not#(==(x#, Int(0))) -> {
println#(String(000))
}
else -> {
}
}
}
public? final? class X {
public? constructor(i: Int): super<kotlin.Any>()
public? final? property i(val): Int
public? get(): Int
}
public? final? function test2(x: X): kotlin.Unit {
val x1: <implicit> = {
val <unary>: <implicit> = x#.i#
x#.i# = inc#(<unary>#)
<unary>#
}
val x2: <implicit> = {
val <unary>: <implicit> = x#.i#
val <unary-result>: <implicit> = inc#(<unary>#)
x#.i# = <unary-result>#
<unary-result>#
}
}
public? final? function test3(arr: Array<Int>): kotlin.Unit {
val x1: <implicit> = {
val <unary>: <implicit> = arr#[Int(0)]
arr#[Int(0)] = inc#(<unary>#)
<unary>#
}
val x2: <implicit> = {
val <unary>: <implicit> = arr#[Int(1)]
val <unary-result>: <implicit> = inc#(<unary>#)
arr#[Int(1)] = <unary-result>#
<unary-result>#
}
}
public? final? class Y {
public? constructor(arr: Array<Int>): super<kotlin.Any>()
public? final? property arr(val): Array<Int>
public? get(): Array<Int>
}
public? final? function test4(y: Y): kotlin.Unit {
val x1: <implicit> = {
val <unary>: <implicit> = y#.arr#[Int(0)]
val <array-set>: <implicit> = y#.arr#
<array-set>#[Int(0)] = inc#(<unary>#)
<unary>#
}
val x2: <implicit> = {
val <unary>: <implicit> = y#.arr#[Int(1)]
val <unary-result>: <implicit> = inc#(<unary>#)
val <array-set>: <implicit> = y#.arr#
<array-set>#[Int(1)] = <unary-result>#
<unary-result>#
}
}
@@ -0,0 +1,8 @@
fun foo() {
val x = 1
var y = x + 1
val z = y * 2
y = y + z
val w = y - x
return w
}
@@ -0,0 +1,9 @@
FILE: variables.kt
public? final? function foo(): kotlin.Unit {
val x: <implicit> = Int(1)
var y: <implicit> = plus#(x#, Int(1))
val z: <implicit> = times#(y#, Int(2))
y# = plus#(y#, z#)
val w: <implicit> = minus#(y#, x#)
return@@@foo w#
}
@@ -0,0 +1,20 @@
fun foo(limit: Int) {
var k = 0
some@ while (k < limit) {
k++
println(k)
while (k == 13) {
k++
if (k < limit) break@some
if (k > limit) continue
}
}
}
fun bar(limit: Int) {
var k = limit
do {
k--
println(k)
} while (k >= 0)
}
@@ -0,0 +1,43 @@
FILE: while.kt
public? final? function foo(limit: Int): kotlin.Unit {
var k: <implicit> = Int(0)
some@while(<(k#, limit#)) {
val <unary>: <implicit> = k#
k# = inc#(<unary>#)
<unary>#
println#(k#)
while(==(k#, Int(13))) {
val <unary>: <implicit> = k#
k# = inc#(<unary>#)
<unary>#
when () {
<(k#, limit#) -> {
break@@@[<(k#, limit#)]
}
else -> {
}
}
when () {
>(k#, limit#) -> {
continue@@@[==(k#, Int(13))]
}
else -> {
}
}
}
}
}
public? final? function bar(limit: Int): kotlin.Unit {
var k: <implicit> = limit#
do {
val <unary>: <implicit> = k#
k# = dec#(<unary>#)
<unary>#
println#(k#)
}
while(>=(k#, Int(0)))
}
@@ -58,7 +58,7 @@ abstract class AbstractRawFirBuilderTestCase : KtParsingTestCase(
protected fun doRawFirTest(filePath: String) {
val file = createKtFile(filePath)
val firFile = file.toFirFile()
val firFile = file.toFirFile(stubMode = false)
val firFileDump = StringBuilder().also { FirRenderer(it).visitFile(firFile) }.toString()
val expectedPath = filePath.replace(".kt", ".txt")
KotlinTestUtils.assertEqualsToFile(File(expectedPath), firFileDump)
@@ -71,8 +71,8 @@ abstract class AbstractRawFirBuilderTestCase : KtParsingTestCase(
}
}
protected fun KtFile.toFirFile(): FirFile =
RawFirBuilder(object : FirSessionBase() {}).buildFirFile(this)
protected fun KtFile.toFirFile(stubMode: Boolean): FirFile =
RawFirBuilder(object : FirSessionBase() {}, stubMode).buildFirFile(this)
private fun FirElement.traverseChildren(result: MutableSet<FirElement> = hashSetOf()): MutableSet<FirElement> {
if (!result.add(this)) {
@@ -130,5 +130,143 @@ public class RawFirBuilderTestCaseGenerated extends AbstractRawFirBuilderTestCas
public void testTypeParameters() throws Exception {
runTest("compiler/fir/psi2fir/testData/rawBuilder/declarations/typeParameters.kt");
}
@TestMetadata("where.kt")
public void testWhere() throws Exception {
runTest("compiler/fir/psi2fir/testData/rawBuilder/declarations/where.kt");
}
}
@TestMetadata("compiler/fir/psi2fir/testData/rawBuilder/expressions")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Expressions extends AbstractRawFirBuilderTestCase {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doRawFirTest, TargetBackend.ANY, testDataFilePath);
}
public void testAllFilesPresentInExpressions() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/fir/psi2fir/testData/rawBuilder/expressions"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("annotated.kt")
public void testAnnotated() throws Exception {
runTest("compiler/fir/psi2fir/testData/rawBuilder/expressions/annotated.kt");
}
@TestMetadata("arrayAccess.kt")
public void testArrayAccess() throws Exception {
runTest("compiler/fir/psi2fir/testData/rawBuilder/expressions/arrayAccess.kt");
}
@TestMetadata("arrayAssignment.kt")
public void testArrayAssignment() throws Exception {
runTest("compiler/fir/psi2fir/testData/rawBuilder/expressions/arrayAssignment.kt");
}
@TestMetadata("branches.kt")
public void testBranches() throws Exception {
runTest("compiler/fir/psi2fir/testData/rawBuilder/expressions/branches.kt");
}
@TestMetadata("callableReferences.kt")
public void testCallableReferences() throws Exception {
runTest("compiler/fir/psi2fir/testData/rawBuilder/expressions/callableReferences.kt");
}
@TestMetadata("calls.kt")
public void testCalls() throws Exception {
runTest("compiler/fir/psi2fir/testData/rawBuilder/expressions/calls.kt");
}
@TestMetadata("classReference.kt")
public void testClassReference() throws Exception {
runTest("compiler/fir/psi2fir/testData/rawBuilder/expressions/classReference.kt");
}
@TestMetadata("collectionLiterals.kt")
public void testCollectionLiterals() throws Exception {
runTest("compiler/fir/psi2fir/testData/rawBuilder/expressions/collectionLiterals.kt");
}
@TestMetadata("destructuring.kt")
public void testDestructuring() throws Exception {
runTest("compiler/fir/psi2fir/testData/rawBuilder/expressions/destructuring.kt");
}
@TestMetadata("for.kt")
public void testFor() throws Exception {
runTest("compiler/fir/psi2fir/testData/rawBuilder/expressions/for.kt");
}
@TestMetadata("genericCalls.kt")
public void testGenericCalls() throws Exception {
runTest("compiler/fir/psi2fir/testData/rawBuilder/expressions/genericCalls.kt");
}
@TestMetadata("init.kt")
public void testInit() throws Exception {
runTest("compiler/fir/psi2fir/testData/rawBuilder/expressions/init.kt");
}
@TestMetadata("lambda.kt")
public void testLambda() throws Exception {
runTest("compiler/fir/psi2fir/testData/rawBuilder/expressions/lambda.kt");
}
@TestMetadata("locals.kt")
public void testLocals() throws Exception {
runTest("compiler/fir/psi2fir/testData/rawBuilder/expressions/locals.kt");
}
@TestMetadata("modifications.kt")
public void testModifications() throws Exception {
runTest("compiler/fir/psi2fir/testData/rawBuilder/expressions/modifications.kt");
}
@TestMetadata("nullability.kt")
public void testNullability() throws Exception {
runTest("compiler/fir/psi2fir/testData/rawBuilder/expressions/nullability.kt");
}
@TestMetadata("simpleReturns.kt")
public void testSimpleReturns() throws Exception {
runTest("compiler/fir/psi2fir/testData/rawBuilder/expressions/simpleReturns.kt");
}
@TestMetadata("super.kt")
public void testSuper() throws Exception {
runTest("compiler/fir/psi2fir/testData/rawBuilder/expressions/super.kt");
}
@TestMetadata("these.kt")
public void testThese() throws Exception {
runTest("compiler/fir/psi2fir/testData/rawBuilder/expressions/these.kt");
}
@TestMetadata("try.kt")
public void testTry() throws Exception {
runTest("compiler/fir/psi2fir/testData/rawBuilder/expressions/try.kt");
}
@TestMetadata("typeOperators.kt")
public void testTypeOperators() throws Exception {
runTest("compiler/fir/psi2fir/testData/rawBuilder/expressions/typeOperators.kt");
}
@TestMetadata("unary.kt")
public void testUnary() throws Exception {
runTest("compiler/fir/psi2fir/testData/rawBuilder/expressions/unary.kt");
}
@TestMetadata("variables.kt")
public void testVariables() throws Exception {
runTest("compiler/fir/psi2fir/testData/rawBuilder/expressions/variables.kt");
}
@TestMetadata("while.kt")
public void testWhile() throws Exception {
runTest("compiler/fir/psi2fir/testData/rawBuilder/expressions/while.kt");
}
}
}
@@ -6,8 +6,19 @@
package org.jetbrains.kotlin.fir.builder
import com.intellij.testFramework.TestDataPath
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.FirRenderer
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.declarations.FirErrorDeclaration
import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.expressions.FirErrorExpression
import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.expressions.FirAccess
import org.jetbrains.kotlin.fir.expressions.FirStatement
import org.jetbrains.kotlin.fir.expressions.impl.FirExpressionStub
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
import org.jetbrains.kotlin.fir.render
import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners
import org.junit.runner.RunWith
import java.io.File
@@ -17,11 +28,19 @@ import kotlin.system.measureNanoTime
@RunWith(JUnit3RunnerWithInners::class)
class RawFirBuilderTotalKotlinTestCase : AbstractRawFirBuilderTestCase() {
fun testTotalKotlin() {
private fun testTotalKotlinWithGivenMode(stubMode: Boolean) {
val root = File(testDataPath)
var counter = 0
var time = 0L
var totalLength = 0
var expressionStubs = 0
var errorExpressions = 0
var normalExpressions = 0
var normalStatements = 0
var errorDeclarations = 0
var normalDeclarations = 0
var errorReferences = 0
var normalReferences = 0
println("BASE PATH: $testDataPath")
for (file in root.walkTopDown()) {
if (file.isDirectory) continue
@@ -31,12 +50,66 @@ class RawFirBuilderTotalKotlinTestCase : AbstractRawFirBuilderTestCase() {
val ktFile = createKtFile(file.toRelativeString(root))
var firFile: FirFile? = null
time += measureNanoTime {
firFile = ktFile.toFirFile()
firFile = ktFile.toFirFile(stubMode)
}
totalLength += StringBuilder().also { FirRenderer(it).visitFile(firFile!!) }.length
counter++
firFile?.accept(object : FirVisitorVoid() {
override fun visitElement(element: FirElement) {
element.acceptChildren(this)
}
override fun visitErrorExpression(errorExpression: FirErrorExpression) {
errorExpressions++
println(errorExpression.render())
errorExpression.psi?.let { println(it) }
}
override fun visitAccess(access: FirAccess) {
val calleeReference = access.calleeReference
if (calleeReference is FirErrorNamedReference) {
errorReferences++
println(calleeReference.errorReason)
} else {
normalReferences++
}
super.visitAccess(access)
}
override fun visitExpression(expression: FirExpression) {
when (expression) {
is FirExpressionStub -> {
expressionStubs++
if (!stubMode) {
println(expression.psi?.text)
}
}
else -> normalExpressions++
}
expression.acceptChildren(this)
}
override fun visitStatement(statement: FirStatement) {
normalStatements++
statement.acceptChildren(this)
}
override fun visitErrorDeclaration(errorDeclaration: FirErrorDeclaration) {
errorDeclarations++
println(errorDeclaration.render())
errorDeclaration.psi?.let { println(it) }
}
override fun visitDeclaration(declaration: FirDeclaration) {
normalDeclarations++
declaration.acceptChildren(this)
}
})
} catch (e: Exception) {
println("TIME PER FILE: ${(time / counter) * 1e-6} ms, COUNTER: $counter")
if (counter > 0) {
println("TIME PER FILE: ${(time / counter) * 1e-6} ms, COUNTER: $counter")
}
println("EXCEPTION in: " + file.toRelativeString(root))
throw e
}
@@ -44,6 +117,28 @@ class RawFirBuilderTotalKotlinTestCase : AbstractRawFirBuilderTestCase() {
println("SUCCESS!")
println("TOTAL LENGTH: $totalLength")
println("TIME PER FILE: ${(time / counter) * 1e-6} ms, COUNTER: $counter")
println("EXPRESSION STUBS: $expressionStubs")
println("ERROR EXPRESSIONS: $errorExpressions")
println("NORMAL EXPRESSIONS: $normalExpressions")
println("NORMAL STATEMENTS: $normalStatements")
println("ERROR DECLARATIONS: $errorDeclarations")
println("NORMAL DECLARATIONS: $normalDeclarations")
println("ERROR REFERENCES: $errorReferences")
println("NORMAL REFERENCES: $normalReferences")
if (!stubMode) {
assertEquals(0, expressionStubs)
}
assertEquals(0, errorExpressions)
assertEquals(0, errorDeclarations)
assertEquals(0, errorReferences)
}
fun testTotalKotlinWithExpressionTrees() {
testTotalKotlinWithGivenMode(stubMode = false)
}
fun testTotalKotlinWithDeclarationsOnly() {
testTotalKotlinWithGivenMode(stubMode = true)
}
fun testVisitConsistency() {
@@ -53,7 +148,7 @@ class RawFirBuilderTotalKotlinTestCase : AbstractRawFirBuilderTestCase() {
if (file.path.contains("testData") || file.path.contains("resources")) continue
if (file.extension != "kt") continue
val ktFile = createKtFile(file.toRelativeString(root))
val firFile = ktFile.toFirFile()
val firFile = ktFile.toFirFile(stubMode = false)
try {
firFile.checkChildren()
} catch (e: Throwable) {
@@ -70,7 +165,7 @@ class RawFirBuilderTotalKotlinTestCase : AbstractRawFirBuilderTestCase() {
if (file.path.contains("testData") || file.path.contains("resources")) continue
if (file.extension != "kt") continue
val ktFile = createKtFile(file.toRelativeString(root))
val firFile = ktFile.toFirFile()
val firFile = ktFile.toFirFile(stubMode = false)
try {
firFile.checkTransformedChildren()
} catch (e: Throwable) {
@@ -44,14 +44,14 @@ class FirProviderImpl(val session: FirSession) : FirProvider {
var containerFqName: FqName = FqName.ROOT
override fun visitClass(klass: FirClass) {
val fqName = containerFqName.child(klass.name)
override fun visitRegularClass(regularClass: FirRegularClass) {
val fqName = containerFqName.child(regularClass.name)
val classId = ClassId(packageName, fqName, false)
classifierMap[classId] = klass
classifierMap[classId] = regularClass
classifierContainerFileMap[classId] = file
containerFqName = fqName
klass.acceptChildren(this)
regularClass.acceptChildren(this)
containerFqName = fqName.parent()
}
@@ -24,7 +24,7 @@ class FirStatusResolveTransformer : FirTransformer<Nothing?>() {
private val declarationsWithStatuses = mutableListOf<FirDeclaration>()
private val classes = mutableListOf<FirClass>()
private val classes = mutableListOf<FirRegularClass>()
private fun FirDeclaration.resolveVisibility(): Visibility {
if (this is FirConstructor) {
@@ -39,7 +39,7 @@ class FirStatusResolveTransformer : FirTransformer<Nothing?>() {
private fun FirDeclaration.resolveModality(): Modality {
return when (this) {
is FirEnumEntry -> Modality.FINAL
is FirClass -> if (classKind == ClassKind.INTERFACE) Modality.ABSTRACT else Modality.FINAL
is FirRegularClass -> if (classKind == ClassKind.INTERFACE) Modality.ABSTRACT else Modality.FINAL
is FirCallableMember -> {
val containingClass = classes.lastOrNull()
when {
@@ -94,7 +94,7 @@ class FirStatusResolveTransformer : FirTransformer<Nothing?>() {
}
private inline fun storeClass(
klass: FirClass,
klass: FirRegularClass,
computeResult: () -> CompositeTransformResult<FirDeclaration>
): CompositeTransformResult<FirDeclaration> {
classes += klass
@@ -103,9 +103,9 @@ class FirStatusResolveTransformer : FirTransformer<Nothing?>() {
return result
}
override fun transformClass(klass: FirClass, data: Nothing?): CompositeTransformResult<FirDeclaration> {
return storeClass(klass) {
super.transformClass(klass, data)
override fun transformRegularClass(regularClass: FirRegularClass, data: Nothing?): CompositeTransformResult<FirDeclaration> {
return storeClass(regularClass) {
super.transformRegularClass(regularClass, data)
}
}
@@ -50,7 +50,7 @@ open class FirTypeResolveTransformer(
return super.transformFile(file, data)
}
private fun lookupSuperTypes(klass: FirClass): List<ConeClassLikeType> {
private fun lookupSuperTypes(klass: FirRegularClass): List<ConeClassLikeType> {
return mutableListOf<ConeClassLikeType>().also { klass.symbol.collectSuperTypes(it) }
}
@@ -63,28 +63,28 @@ open class FirTypeResolveTransformer(
}
}
override fun transformClass(klass: FirClass, data: Nothing?): CompositeTransformResult<FirDeclaration> {
override fun transformRegularClass(regularClass: FirRegularClass, data: Nothing?): CompositeTransformResult<FirDeclaration> {
return withScopeCleanup {
klass.withTypeParametersScope {
resolveSuperTypesAndExpansions(klass)
regularClass.withTypeParametersScope {
resolveSuperTypesAndExpansions(regularClass)
val firProvider = FirProvider.getInstance(klass.session)
val classId = klass.symbol.classId
val firProvider = FirProvider.getInstance(regularClass.session)
val classId = regularClass.symbol.classId
scope.scopes += FirNestedClassifierScope(classId, firProvider)
val companionObjects = klass.declarations.filterIsInstance<FirClass>().filter { it.isCompanion }
val companionObjects = regularClass.declarations.filterIsInstance<FirRegularClass>().filter { it.isCompanion }
for (companionObject in companionObjects) {
scope.scopes += FirNestedClassifierScope(companionObject.symbol.classId, firProvider)
}
lookupSuperTypes(klass).mapTo(scope.scopes) {
lookupSuperTypes(regularClass).mapTo(scope.scopes) {
val symbol = it.symbol
if (symbol is FirBasedSymbol<*>) {
FirNestedClassifierScope(symbol.classId, FirProvider.getInstance(symbol.fir.session))
} else {
FirNestedClassifierScope(symbol.classId, FirSymbolProvider.getInstance(klass.session))
FirNestedClassifierScope(symbol.classId, FirSymbolProvider.getInstance(regularClass.session))
}
}
super.transformClass(klass, data)
super.transformRegularClass(regularClass, data)
}
}
}
+2 -2
View File
@@ -8,8 +8,8 @@ FILE: lists.kt
}
public final function convert R|kotlin/collections/List<kotlin/String>|.(): R|MyStringList| {
STUB
return@@@convert STUB
}
public final function ret(l: R|kotlin/collections/MutableList<kotlin/String>|): R|MyMutableStringList| {
STUB
return@@@ret STUB
}
+1 -1
View File
@@ -11,5 +11,5 @@ FILE: derivedClass.kt
}
<T : R|kotlin/Any|> public final function create(x: R|T|): R|Derived<T>| {
STUB
return@@@create STUB
}
+2 -2
View File
@@ -19,7 +19,7 @@ FILE: enum.kt
public constructor(): super<R|SomeEnum|>()
public final override function check(y: R|Some|): R|kotlin/Boolean| {
STUB
return@@@check STUB
}
}
@@ -28,7 +28,7 @@ FILE: enum.kt
public constructor(): super<R|SomeEnum|>()
public final override function check(y: R|Some|): R|kotlin/Boolean| {
STUB
return@@@check STUB
}
}
@@ -31,6 +31,7 @@ FILE: enums.kt
public constructor(): super<R|Planet|>()
public final override function sayHello(): R|kotlin/Unit| {
return@@@sayHello STUB
}
}
@@ -39,6 +40,7 @@ FILE: enums.kt
public constructor(): super<R|Planet|>()
public final override function sayHello(): R|kotlin/Unit| {
return@@@sayHello STUB
}
}
@@ -47,6 +49,7 @@ FILE: enums.kt
public constructor(): super<R|Planet|>()
public final override function sayHello(): R|kotlin/Unit| {
return@@@sayHello STUB
}
}
@@ -4,6 +4,7 @@ FILE: noPrimaryConstructor.kt
public get(): R|kotlin/String|
public constructor(x: R|kotlin/String|): super<R|kotlin/Any|>() {
return STUB
}
public constructor(): this<R|NoPrimary|>()
@@ -13,13 +13,15 @@ FILE: simpleClass.kt
private get(): R|error: Not supported: FirImplicitTypeImpl|
public final override function foo(x: R|kotlin/Int|, y: R|kotlin/String|): R|kotlin/String| {
return@@@foo STUB
}
public final override property bar(var): R|kotlin/Boolean|
public get(): R|kotlin/Boolean| {
STUB
return STUB
}
public set(value: R|kotlin/Boolean|): R|kotlin/Unit| {
return STUB
}
public final lateinit property fau(var): R|kotlin/Double|
@@ -15,11 +15,11 @@ FILE: typeParameters.kt
public constructor(): super<R|AbstractList<kotlin/Int>|>()
public final override function get(index: R|kotlin/Int|): R|kotlin/Int| {
STUB
return@@@get STUB
}
public final override function concat(other: R|List<kotlin/Int>|): R|List<kotlin/Int>| {
STUB
return@@@concat STUB
}
}
+3 -2
View File
@@ -1,11 +1,12 @@
FILE: functionTypes.kt
<T> public final function simpleRun(f: R|(T) -> kotlin/Unit|): R|kotlin/Unit| {
STUB
return@@@simpleRun STUB
}
<T, R> public final function simpleMap R|kotlin/collections/List<T>|.(f: R|(T) -> R|): R|R| {
return@@@simpleMap STUB
}
<T> public final function simpleWith(t: R|T|, f: R|T.() -> kotlin/Unit|): R|kotlin/Unit| {
STUB
return@@@simpleWith STUB
}
<T, R> public abstract interface KMutableProperty1 : R|KProperty1<T, R>|, R|KMutableProperty<R>| {
}
+1 -1
View File
@@ -2,7 +2,7 @@ FILE: genericFunctions.kt
public abstract interface Any {
}
<reified T : R|Any|> public final inline function safeAs R|Any|.(): R|T| {
STUB
return@@@safeAs STUB
}
public abstract class Summator {
public constructor(): super<R|Any|>()
@@ -16,11 +16,12 @@ FILE: Annotations.kt
public get(): R|kotlin/Char|
public final override function foo(arg: R|kotlin/Double|): R|kotlin/Unit| {
return@@@foo STUB
}
public final override property v(val): R|kotlin/String|
@R|annotations/Simple|() public get(): R|kotlin/String| {
STUB
return STUB
}
@R|annotations/WithString|(String(constructor)) public constructor(): this<R|test/Second|>()
+3 -1
View File
@@ -13,13 +13,15 @@ FILE: simpleClass.kt
private get(): R|error: Not supported: FirImplicitTypeImpl|
public final override function foo(x: R|kotlin/Int|, y: R|kotlin/String|): R|kotlin/String| {
return@@@foo STUB
}
public final override property bar(var): R|kotlin/Boolean|
public get(): R|kotlin/Boolean| {
STUB
return STUB
}
public set(value: R|kotlin/Boolean|): R|kotlin/Unit| {
return STUB
}
public final property fau(var): R|kotlin/Double|
@@ -3,4 +3,5 @@ FILE: concurrent.kt
public get(): R|kotlin/Int|
public set(value: R|kotlin/Int|): R|kotlin/Unit|
@R|kotlin/jvm/Synchronized|() public final function foo(): R|kotlin/Unit| {
return@@@foo STUB
}
@@ -7,6 +7,7 @@ FILE: functionX.kt
public constructor(): super<R|kotlin/Any|>()
public final override function invoke(p1: R|kotlin/Int|, p2: R|kotlin/String|): R|kotlin/Unit| {
return@@@invoke STUB
}
}
@@ -1,5 +1,5 @@
FILE: typeParameterInPropertyReceiver.kt
<T : R|kotlin/Any|> public final property self R|T|.(val): R|T|
public get(): R|T| {
STUB
return STUB
}
@@ -29,7 +29,7 @@ abstract class AbstractFirResolveTestCase : AbstractFirResolveWithSessionTestCas
.uniteWith(TopDownAnalyzerFacadeForJVM.AllJavaSourcesInProjectScope(project))
val session = createSession(scope)
val builder = RawFirBuilder(session)
val builder = RawFirBuilder(session, stubMode = true)
val transformer = FirTotalResolveTransformer()
return ktFiles.map {
@@ -65,7 +65,7 @@ class FirResolveTestTotalKotlin : AbstractFirResolveWithSessionTestCase() {
val scope = ProjectScope.getContentScope(project)
val session = createSession(scope)
val builder = RawFirBuilder(session)
val builder = RawFirBuilder(session, stubMode = true)
val totalTransformer = FirTotalResolveTransformer()
val firFiles = ktFiles.map {
@@ -0,0 +1,15 @@
/*
* Copyright 2010-2019 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
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.expressions.FirExpression
abstract class FirAbstractElement(
final override val session: FirSession,
final override val psi: PsiElement?
) : FirElement
@@ -0,0 +1,16 @@
/*
* Copyright 2010-2019 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
abstract class FirAbstractTarget<E : FirTargetElement>(
override val labelName: String?
) : FirTarget<E> {
override lateinit var labeledElement: E
override fun bind(element: E) {
labeledElement = element
}
}
@@ -0,0 +1,12 @@
/*
* Copyright 2010-2019 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
import org.jetbrains.kotlin.fir.declarations.FirFunction
class FirFunctionTarget(
labelName: String?
) : FirAbstractTarget<FirFunction>(labelName)
@@ -0,0 +1,15 @@
/*
* Copyright 2010-2019 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
import org.jetbrains.kotlin.fir.visitors.FirVisitor
interface FirLabel : FirElement {
val name: String
override fun <R, D> accept(visitor: FirVisitor<R, D>, data: D): R =
visitor.visitLabel(this, data)
}
@@ -0,0 +1,21 @@
/*
* Copyright 2010-2019 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
import org.jetbrains.kotlin.fir.visitors.FirVisitor
// Target element which may have label
interface FirLabeledElement : FirTargetElement {
val label: FirLabel? get() = null
override fun <R, D> accept(visitor: FirVisitor<R, D>, data: D): R =
visitor.visitLabeledElement(this, data)
override fun <R, D> acceptChildren(visitor: FirVisitor<R, D>, data: D) {
label?.accept(visitor, data)
}
}
@@ -0,0 +1,12 @@
/*
* Copyright 2010-2019 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
import org.jetbrains.kotlin.fir.expressions.FirLoop
class FirLoopTarget(
labelName: String?
) : FirAbstractTarget<FirLoop>(labelName)
@@ -0,0 +1,16 @@
/*
* Copyright 2010-2019 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
import org.jetbrains.kotlin.fir.visitors.FirVisitor
import org.jetbrains.kotlin.name.Name
interface FirNamedReference : FirReference {
val name: Name
override fun <R, D> accept(visitor: FirVisitor<R, D>, data: D): R =
visitor.visitNamedReference(this, data)
}
@@ -0,0 +1,13 @@
/*
* Copyright 2010-2019 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
import org.jetbrains.kotlin.fir.visitors.FirVisitor
interface FirReference : FirElement {
override fun <R, D> accept(visitor: FirVisitor<R, D>, data: D): R =
visitor.visitReference(this, data)
}
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.expressions.impl.*
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeSymbol
import org.jetbrains.kotlin.fir.symbols.ConeSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
@@ -141,7 +142,7 @@ class FirRenderer(builder: StringBuilder) : FirVisitorVoid() {
if (memberDeclaration is FirCallableMember && memberDeclaration.isOverride) {
print("override ")
}
if (memberDeclaration is FirClass) {
if (memberDeclaration is FirRegularClass) {
if (memberDeclaration.isInner) {
print("inner ")
}
@@ -193,35 +194,62 @@ class FirRenderer(builder: StringBuilder) : FirVisitorVoid() {
override fun visitDeclaration(declaration: FirDeclaration) {
print(
when (declaration) {
is FirClass -> declaration.classKind.name.toLowerCase().replace("_", " ")
is FirRegularClass -> declaration.classKind.name.toLowerCase().replace("_", " ")
is FirTypeAlias -> "typealias"
is FirNamedFunction -> "function"
is FirProperty -> "property"
is FirVariable -> if (declaration.isVal) "val" else "var"
else -> "unknown"
}
)
}
override fun visitEnumEntry(enumEntry: FirEnumEntry) {
visitClass(enumEntry)
visitRegularClass(enumEntry)
}
override fun visitClass(klass: FirClass) {
visitMemberDeclaration(klass)
if (klass.superTypes.isNotEmpty()) {
print(" : ")
klass.superTypes.renderSeparated()
}
private fun FirDeclarationContainer.renderDeclarations() {
println(" {")
pushIndent()
for (declaration in klass.declarations) {
declaration.accept(this)
for (declaration in declarations) {
declaration.accept(this@FirRenderer)
println()
}
popIndent()
println("}")
}
override fun visitRegularClass(regularClass: FirRegularClass) {
visitMemberDeclaration(regularClass)
if (regularClass.superTypes.isNotEmpty()) {
print(" : ")
regularClass.superTypes.renderSeparated()
}
regularClass.renderDeclarations()
}
override fun visitAnonymousObject(anonymousObject: FirAnonymousObject) {
anonymousObject.annotations.renderAnnotations()
print("object : ")
anonymousObject.superTypes.renderSeparated()
anonymousObject.renderDeclarations()
}
override fun visitVariable(variable: FirVariable) {
variable.annotations.renderAnnotations()
visitNamedDeclaration(variable)
print(": ")
variable.returnType.accept(this)
variable.initializer?.let {
print(" = ")
it.accept(this)
}
variable.delegate?.let {
print("by ")
it.accept(this)
}
}
override fun visitProperty(property: FirProperty) {
visitCallableMember(property)
property.initializer?.let {
@@ -276,6 +304,26 @@ class FirRenderer(builder: StringBuilder) : FirVisitorVoid() {
propertyAccessor.body?.accept(this)
}
override fun visitAnonymousFunction(anonymousFunction: FirAnonymousFunction) {
anonymousFunction.annotations.renderAnnotations()
val label = anonymousFunction.label
if (label != null) {
print("${label.name}@")
}
print("function ")
val receiverType = anonymousFunction.receiverType
if (receiverType != null) {
print(" ")
receiverType.accept(this)
print(".")
}
print("<anonymous>")
anonymousFunction.valueParameters.renderParameters()
print(": ")
anonymousFunction.returnType.accept(this)
anonymousFunction.body?.accept(this)
}
override fun visitFunction(function: FirFunction) {
function.valueParameters.renderParameters()
visitDeclarationWithBody(function)
@@ -291,10 +339,10 @@ class FirRenderer(builder: StringBuilder) : FirVisitorVoid() {
declarationWithBody.body?.accept(this)
}
override fun visitBody(body: FirBody) {
override fun visitBlock(block: FirBlock) {
println(" {")
pushIndent()
for (statement in body.statements) {
for (statement in block.statements) {
statement.accept(this)
println()
}
@@ -348,10 +396,6 @@ class FirRenderer(builder: StringBuilder) : FirVisitorVoid() {
}
}
override fun visitVariable(variable: FirVariable) {
visitDeclaration(variable)
}
override fun visitImport(import: FirImport) {
visitElement(import)
}
@@ -360,11 +404,128 @@ class FirRenderer(builder: StringBuilder) : FirVisitorVoid() {
visitElement(statement)
}
override fun visitReturnExpression(returnExpression: FirReturnExpression) {
returnExpression.annotations.renderAnnotations()
print("return")
val target = returnExpression.target
val labeledElement = target.labeledElement
if (labeledElement is FirNamedFunction) {
print("@@@${labeledElement.name}")
} else {
val labelName = target.labelName
if (labelName != null) {
if (labeledElement is FirAnonymousFunction) {
print("@@")
}
print("@$labelName")
}
}
print(" ")
returnExpression.result.accept(this)
}
override fun visitWhenBranch(whenBranch: FirWhenBranch) {
val condition = whenBranch.condition
if (condition is FirElseIfTrueCondition) {
print("else")
} else {
condition.accept(this)
}
print(" -> ")
whenBranch.result.accept(this)
}
override fun visitWhenExpression(whenExpression: FirWhenExpression) {
whenExpression.annotations.renderAnnotations()
print("when (")
val subjectVariable = whenExpression.subjectVariable
if (subjectVariable != null) {
subjectVariable.accept(this)
} else {
whenExpression.subject?.accept(this)
}
println(") {")
pushIndent()
for (branch in whenExpression.branches) {
branch.accept(this)
}
popIndent()
println("}")
}
override fun visitTryExpression(tryExpression: FirTryExpression) {
tryExpression.annotations.renderAnnotations()
print("try")
tryExpression.tryBlock.accept(this)
for (catchClause in tryExpression.catches) {
print("catch (")
catchClause.parameter.accept(this)
print(")")
catchClause.block.accept(this)
}
val finallyBlock = tryExpression.finallyBlock ?: return
print("finally")
finallyBlock.accept(this)
}
override fun visitDoWhileLoop(doWhileLoop: FirDoWhileLoop) {
val label = doWhileLoop.label
if (label != null) {
print("${label.name}@")
}
print("do")
doWhileLoop.block.accept(this)
print("while(")
doWhileLoop.condition.accept(this)
print(")")
}
override fun visitWhileLoop(whileLoop: FirWhileLoop) {
val label = whileLoop.label
if (label != null) {
print("${label.name}@")
}
print("while(")
whileLoop.condition.accept(this)
print(")")
whileLoop.block.accept(this)
}
private fun visitLoopJump(jump: FirJump<FirLoop>) {
val target = jump.target
val labeledElement = target.labeledElement
print("@@@[")
labeledElement.condition.accept(this)
print("] ")
}
override fun visitBreakExpression(breakExpression: FirBreakExpression) {
breakExpression.annotations.renderAnnotations()
print("break")
visitLoopJump(breakExpression)
}
override fun visitContinueExpression(continueExpression: FirContinueExpression) {
continueExpression.annotations.renderAnnotations()
print("continue")
visitLoopJump(continueExpression)
}
override fun visitExpression(expression: FirExpression) {
print("STUB")
expression.annotations.renderAnnotations()
print(
when (expression) {
is FirExpressionStub -> "STUB"
is FirUnitExpression -> "Unit"
is FirWhenSubjectExpression -> "\$subj\$"
is FirElseIfTrueCondition -> "else"
else -> "??? ${expression.javaClass}"
}
)
}
override fun <T> visitConstExpression(constExpression: FirConstExpression<T>) {
constExpression.annotations.renderAnnotations()
print("${constExpression.kind}(${constExpression.value})")
}
@@ -406,7 +567,7 @@ class FirRenderer(builder: StringBuilder) : FirVisitorVoid() {
}
override fun visitDelegatedType(delegatedType: FirDelegatedType) {
delegatedType.accept(this)
delegatedType.type.accept(this)
print(" by ")
delegatedType.delegate?.accept(this)
}
@@ -460,7 +621,7 @@ class FirRenderer(builder: StringBuilder) : FirVisitorVoid() {
val sb = StringBuilder()
sb.append(symbol.classId.asString())
if (typeArguments.isNotEmpty()) {
sb.append(typeArguments.joinToString(prefix = "<", postfix = ">") { it ->
sb.append(typeArguments.joinToString(prefix = "<", postfix = ">") {
when (it) {
StarProjection -> "*"
is ConeKotlinTypeProjectionIn -> "in ${it.type.asString()}"
@@ -530,4 +691,130 @@ class FirRenderer(builder: StringBuilder) : FirVisitorVoid() {
print("*")
}
override fun visitNamedReference(namedReference: FirNamedReference) {
print("${namedReference.name}#")
}
override fun visitThisReference(thisReference: FirThisReference) {
print("this")
val labelName = thisReference.labelName
if (labelName != null) {
print("@$labelName")
} else {
print("#")
}
}
override fun visitSuperReference(superReference: FirSuperReference) {
print("super<")
superReference.superType.accept(this)
print(">")
}
override fun visitAccess(access: FirAccess) {
val explicitReceiver = access.explicitReceiver
if (explicitReceiver != null) {
explicitReceiver.accept(this)
if (access.safe) {
print("?.")
} else {
print(".")
}
}
}
override fun visitCallableReferenceAccess(callableReferenceAccess: FirCallableReferenceAccess) {
callableReferenceAccess.annotations.renderAnnotations()
callableReferenceAccess.explicitReceiver?.accept(this)
print("::")
callableReferenceAccess.calleeReference.accept(this)
}
override fun visitAccessExpression(accessExpression: FirAccessExpression) {
accessExpression.annotations.renderAnnotations()
visitAccess(accessExpression)
accessExpression.calleeReference.accept(this)
}
override fun visitAssignment(assignment: FirAssignment) {
print(assignment.operation.operator)
print(" ")
assignment.value.accept(this)
}
override fun visitPropertyAssignment(propertyAssignment: FirPropertyAssignment) {
propertyAssignment.annotations.renderAnnotations()
visitAccess(propertyAssignment)
propertyAssignment.calleeReference.accept(this)
print(" ")
visitAssignment(propertyAssignment)
}
override fun visitArraySetCall(arraySetCall: FirArraySetCall) {
arraySetCall.annotations.renderAnnotations()
visitAccess(arraySetCall)
arraySetCall.calleeReference.accept(this)
print("[")
arraySetCall.arguments.renderSeparated()
print("] ")
visitAssignment(arraySetCall)
}
override fun visitFunctionCall(functionCall: FirFunctionCall) {
functionCall.annotations.renderAnnotations()
visitAccess(functionCall)
functionCall.calleeReference.accept(this)
if (functionCall.typeArguments.isNotEmpty()) {
print("<")
functionCall.typeArguments.renderSeparated()
print(">")
}
visitCall(functionCall)
}
override fun visitOperatorCall(operatorCall: FirOperatorCall) {
operatorCall.annotations.renderAnnotations()
print(operatorCall.operation.operator)
if (operatorCall is FirTypeOperatorCall) {
print("/")
operatorCall.type.accept(this)
}
visitCall(operatorCall)
}
override fun visitArrayGetCall(arrayGetCall: FirArrayGetCall) {
arrayGetCall.annotations.renderAnnotations()
arrayGetCall.array.accept(this)
print("[")
arrayGetCall.arguments.renderSeparated()
print("]")
}
override fun visitComponentCall(componentCall: FirComponentCall) {
componentCall.annotations.renderAnnotations()
print("component${componentCall.componentIndex}")
visitCall(componentCall)
}
override fun visitGetClassCall(getClassCall: FirGetClassCall) {
getClassCall.annotations.renderAnnotations()
print("<getClass>")
visitCall(getClassCall)
}
override fun visitArrayOfCall(arrayOfCall: FirArrayOfCall) {
arrayOfCall.annotations.renderAnnotations()
print("<implicitArrayOf>")
visitCall(arrayOfCall)
}
override fun visitThrowExpression(throwExpression: FirThrowExpression) {
throwExpression.annotations.renderAnnotations()
print("throw ")
throwExpression.exception.accept(this)
}
override fun visitErrorExpression(errorExpression: FirErrorExpression) {
print("ERROR_EXPR(${errorExpression.reason})")
}
}
@@ -0,0 +1,20 @@
/*
* Copyright 2010-2019 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
import org.jetbrains.kotlin.fir.types.FirType
import org.jetbrains.kotlin.fir.visitors.FirVisitor
interface FirSuperReference : FirReference {
val superType: FirType
override fun <R, D> accept(visitor: FirVisitor<R, D>, data: D): R =
visitor.visitSuperReference(this, data)
override fun <R, D> acceptChildren(visitor: FirVisitor<R, D>, data: D) {
superType.accept(visitor, data)
}
}
@@ -0,0 +1,15 @@
/*
* Copyright 2010-2019 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
// Reference to some label
interface FirTarget<E : FirTargetElement> {
val labelName: String?
val labeledElement: E
fun bind(element: E)
}
@@ -0,0 +1,9 @@
/*
* Copyright 2010-2019 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
// Any target of return / break / continue (some targets may have labels, some never have them)
interface FirTargetElement : FirElement
@@ -0,0 +1,15 @@
/*
* Copyright 2010-2019 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
import org.jetbrains.kotlin.fir.visitors.FirVisitor
interface FirThisReference : FirReference {
val labelName: String?
override fun <R, D> accept(visitor: FirVisitor<R, D>, data: D): R =
visitor.visitThisReference(this, data)
}
@@ -0,0 +1,30 @@
/*
* Copyright 2010-2019 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.declarations
import org.jetbrains.kotlin.fir.FirLabeledElement
import org.jetbrains.kotlin.fir.VisitedSupertype
import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.types.FirType
import org.jetbrains.kotlin.fir.visitors.FirVisitor
interface FirAnonymousFunction : @VisitedSupertype FirFunction, FirExpression, FirTypedDeclaration, FirLabeledElement {
val receiverType: FirType?
override fun <R, D> accept(visitor: FirVisitor<R, D>, data: D): R =
visitor.visitAnonymousFunction(this, data)
override fun <R, D> acceptChildren(visitor: FirVisitor<R, D>, data: D) {
super<FirTypedDeclaration>.acceptChildren(visitor, data)
super<FirLabeledElement>.acceptChildren(visitor, data)
receiverType?.accept(visitor, data)
for (parameter in valueParameters) {
parameter.accept(visitor, data)
}
body?.accept(visitor, data)
// Don't call super<FirExpression>.acceptChildren (annotations are already processed)
}
}
@@ -0,0 +1,24 @@
/*
* Copyright 2010-2019 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.declarations
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.fir.VisitedSupertype
import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.visitors.FirVisitor
interface FirAnonymousObject : @VisitedSupertype FirClass, FirExpression {
override val classKind: ClassKind
get() = ClassKind.OBJECT
override fun <R, D> accept(visitor: FirVisitor<R, D>, data: D): R =
visitor.visitAnonymousObject(this, data)
override fun <R, D> acceptChildren(visitor: FirVisitor<R, D>, data: D) {
super<FirClass>.acceptChildren(visitor, data)
super<FirExpression>.acceptChildren(visitor, data)
}
}
@@ -1,41 +1,26 @@
/*
* Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* Copyright 2010-2019 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.declarations
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.fir.BaseTransformedType
import org.jetbrains.kotlin.fir.symbols.FirSymbolOwner
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
import org.jetbrains.kotlin.fir.expressions.FirAnnotationContainer
import org.jetbrains.kotlin.fir.expressions.FirStatement
import org.jetbrains.kotlin.fir.types.FirType
import org.jetbrains.kotlin.fir.visitors.FirVisitor
// May be all containers should be properties and not base classes
// About descriptors: introduce something like FirDescriptor which is FirUnresolved at the beginning and FirSymbol(descriptor) at the end
@BaseTransformedType
interface FirClass : FirDeclarationContainer, FirMemberDeclaration, FirSymbolOwner<FirClass> {
interface FirClass : FirDeclarationContainer, FirStatement, FirAnnotationContainer {
// including delegated types
val superTypes: List<FirType>
val classKind: ClassKind
val isInner: Boolean get() = status.isInner
val isCompanion: Boolean get() = status.isCompanion
val isData: Boolean get() = status.isData
val isInline: Boolean get() = status.isInline
override val symbol: FirClassSymbol
override fun <R, D> accept(visitor: FirVisitor<R, D>, data: D): R =
visitor.visitClass(this, data)
override fun <R, D> acceptChildren(visitor: FirVisitor<R, D>, data: D) {
super.acceptChildren(visitor, data)
for (superType in superTypes) {
superType.accept(visitor, data)
}

Some files were not shown because too many files have changed in this diff Show More