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) {