Partial raw FIR building

This commit is contained in:
Roman Golyshev
2020-06-18 17:48:34 +03:00
committed by Ilya Kirillov
parent a1b621d987
commit 6129f4bcef
13 changed files with 186 additions and 9 deletions
@@ -44,9 +44,7 @@ import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType import org.jetbrains.kotlin.psi.psiUtil.*
import org.jetbrains.kotlin.psi.psiUtil.hasActualModifier
import org.jetbrains.kotlin.psi.psiUtil.hasExpectModifier
import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.types.expressions.OperatorConventions import org.jetbrains.kotlin.types.expressions.OperatorConventions
import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlin.util.OperatorNameConventions
@@ -66,6 +64,23 @@ class RawFirBuilder(
return reference.accept(Visitor(), Unit) as FirTypeRef return reference.accept(Visitor(), Unit) as FirTypeRef
} }
fun buildFunctionWithBody(function: KtNamedFunction): FirFunction<*> {
assert(!stubMode) { "Building FIR function with body isn't supported in stub mode" }
val parentsUpToFile = function.parents
for (parent in parentsUpToFile.toList().asReversed()) {
when (parent) {
is KtFile -> {
context.packageFqName = parent.packageFqName
}
is KtClassOrObject -> {
context.className = context.className.child(parent.nameAsSafeName)
context.localBits.add(parent.isLocal || parent.getStrictParentOfType<KtEnumEntry>() != null)
}
}
}
return function.accept(Visitor(), Unit) as FirFunction<*>
}
override fun PsiElement.toFirSourceElement(kind: FirFakeSourceElementKind?): FirPsiSourceElement<*> { override fun PsiElement.toFirSourceElement(kind: FirFakeSourceElementKind?): FirPsiSourceElement<*> {
val actualKind = kind ?: this@RawFirBuilder.context.forcedElementSourceKind ?: FirRealSourceElementKind val actualKind = kind ?: this@RawFirBuilder.context.forcedElementSourceKind ?: FirRealSourceElementKind
return this.toFirPsiSourceElement(actualKind) return this.toFirPsiSourceElement(actualKind)
@@ -0,0 +1,15 @@
// FUNCTION: bar
package test.locals
class Owner {
fun foo(i: Int) {
var x = true
fun bar() {
baz(i, x)
}
}
fun baz(j: Int, y: Boolean) {}
}
@@ -0,0 +1,3 @@
local final? fun <local>/bar(): R|kotlin/Unit| {
baz#(i#, x#)
}
@@ -0,0 +1,15 @@
// FUNCTION: foo
package test.classes
class Outer {
inner class Inner {
fun bar()
fun foo() {
val outer = Outer()
val inner = outer.Inner()
inner.bar()
}
}
}
@@ -0,0 +1,5 @@
public? final? fun test/classes/Outer.Inner.foo(): R|kotlin/Unit| {
lval <local>/outer: <implicit> = Outer#()
lval <local>/inner: <implicit> = outer#.Inner#()
inner#.bar#()
}
@@ -0,0 +1,11 @@
// FUNCTION: foo
package test
fun bar(): Int {
return -1
}
fun foo(): Int {
return 0
}
@@ -0,0 +1,3 @@
public? final? fun test/foo(): Int {
^foo IntegerLiteral(0)
}
@@ -0,0 +1,38 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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 org.jetbrains.kotlin.fir.FirRenderer
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.render
import org.jetbrains.kotlin.psi.KtNamedFunction
import org.jetbrains.kotlin.psi.psiUtil.findDescendantOfType
import org.jetbrains.kotlin.test.KotlinTestUtils
import java.io.File
abstract class AbstractPartialRawFirBuilderTestCase : AbstractRawFirBuilderTestCase() {
override fun doRawFirTest(filePath: String) {
val nameToFind = File(filePath).useLines {
it.first().run {
assert(startsWith(Companion.prefix))
drop(Companion.prefix.length)
}
}
val file = createKtFile(filePath)
val functionToBuild = file.findDescendantOfType<KtNamedFunction> { it.name == nameToFind }!!
val firFunction = RawFirBuilder(
object : FirSession(null) {}, StubFirScopeProvider, false
).buildFunctionWithBody(functionToBuild)
val firDump = firFunction.render(FirRenderer.RenderMode.WithFqNames)
val expectedPath = filePath.replace(".kt", ".txt")
KotlinTestUtils.assertEqualsToFile(File(expectedPath), firDump)
}
companion object {
private const val prefix = "// FUNCTION: "
}
}
@@ -60,7 +60,7 @@ abstract class AbstractRawFirBuilderTestCase : KtParsingTestCase(
} }
} }
protected fun doRawFirTest(filePath: String) { protected open fun doRawFirTest(filePath: String) {
val file = createKtFile(filePath) val file = createKtFile(filePath)
val firFile = file.toFirFile(stubMode = false) val firFile = file.toFirFile(stubMode = false)
val firFileDump = StringBuilder().also { FirRenderer(it).visitFile(firFile) }.toString() val firFileDump = StringBuilder().also { FirRenderer(it).visitFile(firFile) }.toString()
@@ -0,0 +1,45 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
import org.jetbrains.kotlin.test.KotlinTestUtils;
import org.jetbrains.kotlin.test.TestMetadata;
import org.junit.runner.RunWith;
import java.io.File;
import java.util.regex.Pattern;
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all")
@TestMetadata("compiler/fir/raw-fir/psi2fir/testData/partialRawBuilder")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public class PartialRawFirBuilderTestCaseGenerated extends AbstractPartialRawFirBuilderTestCase {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doRawFirTest, this, testDataFilePath);
}
public void testAllFilesPresentInPartialRawBuilder() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/raw-fir/psi2fir/testData/partialRawBuilder"), Pattern.compile("^(.+)\\.kt$"), null, true);
}
@TestMetadata("local.kt")
public void testLocal() throws Exception {
runTest("compiler/fir/raw-fir/psi2fir/testData/partialRawBuilder/local.kt");
}
@TestMetadata("member.kt")
public void testMember() throws Exception {
runTest("compiler/fir/raw-fir/psi2fir/testData/partialRawBuilder/member.kt");
}
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
runTest("compiler/fir/raw-fir/psi2fir/testData/partialRawBuilder/simple.kt");
}
}
@@ -119,7 +119,9 @@ fun CFGNode<*>.render(): String =
) )
} }
private object CfgRenderMode : FirRenderer.RenderMode(renderLambdaBodies = false, renderCallArguments = false) private object CfgRenderMode : FirRenderer.RenderMode(
renderLambdaBodies = false, renderCallArguments = false, renderCallableFqNames = false
)
private fun FirFunction<*>.name(): String = when (this) { private fun FirFunction<*>.name(): String = when (this) {
is FirSimpleFunction -> name.asString() is FirSimpleFunction -> name.asString()
@@ -50,8 +50,14 @@ class FirRenderer(builder: StringBuilder, private val mode: RenderMode = RenderM
) )
} }
abstract class RenderMode(val renderLambdaBodies: Boolean, val renderCallArguments: Boolean) { abstract class RenderMode(
object Normal : RenderMode(renderLambdaBodies = true, renderCallArguments = true) val renderLambdaBodies: Boolean,
val renderCallArguments: Boolean,
val renderCallableFqNames: Boolean
) {
object Normal : RenderMode(renderLambdaBodies = true, renderCallArguments = true, renderCallableFqNames = false)
object WithFqNames: RenderMode(renderLambdaBodies = true, renderCallArguments = true, renderCallableFqNames = true)
} }
private val printer = Printer(builder) private val printer = Printer(builder)
@@ -150,8 +156,20 @@ class FirRenderer(builder: StringBuilder, private val mode: RenderMode = RenderM
print(".") print(".")
} }
when (callableDeclaration) { when (callableDeclaration) {
is FirSimpleFunction -> print(callableDeclaration.name) is FirSimpleFunction -> {
is FirVariable<*> -> print(callableDeclaration.name) if (!mode.renderCallableFqNames) {
print(callableDeclaration.name)
} else {
print(callableDeclaration.symbol.callableId)
}
}
is FirVariable<*> -> {
if (!mode.renderCallableFqNames) {
print(callableDeclaration.name)
} else {
print(callableDeclaration.symbol.callableId)
}
}
} }
if (callableDeclaration is FirFunction<*>) { if (callableDeclaration is FirFunction<*>) {
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.codegen.defaultConstructor.AbstractDefaultArgumentsR
import org.jetbrains.kotlin.codegen.flags.AbstractWriteFlagsTest import org.jetbrains.kotlin.codegen.flags.AbstractWriteFlagsTest
import org.jetbrains.kotlin.codegen.ir.* import org.jetbrains.kotlin.codegen.ir.*
import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.builder.AbstractPartialRawFirBuilderTestCase
import org.jetbrains.kotlin.fir.builder.AbstractRawFirBuilderTestCase import org.jetbrains.kotlin.fir.builder.AbstractRawFirBuilderTestCase
import org.jetbrains.kotlin.fir.java.AbstractFirOldFrontendLightClassesTest import org.jetbrains.kotlin.fir.java.AbstractFirOldFrontendLightClassesTest
import org.jetbrains.kotlin.fir.java.AbstractFirTypeEnhancementTest import org.jetbrains.kotlin.fir.java.AbstractFirTypeEnhancementTest
@@ -544,6 +545,12 @@ fun main(args: Array<String>) {
} }
} }
testGroup("compiler/fir/raw-fir/psi2fir/tests", "compiler/fir/raw-fir/psi2fir/testData") {
testClass<AbstractPartialRawFirBuilderTestCase> {
model("partialRawBuilder", testMethod = "doRawFirTest")
}
}
testGroup("compiler/fir/raw-fir/light-tree2fir/tests", "compiler/fir/raw-fir/psi2fir/testData") { testGroup("compiler/fir/raw-fir/light-tree2fir/tests", "compiler/fir/raw-fir/psi2fir/testData") {
testClass<AbstractLightTree2FirConverterTestCase> { testClass<AbstractLightTree2FirConverterTestCase> {
model("rawBuilder") model("rawBuilder")