From 6129f4bcef2273350e62afb94229187cd75054e0 Mon Sep 17 00:00:00 2001 From: Roman Golyshev Date: Thu, 18 Jun 2020 17:48:34 +0300 Subject: [PATCH] Partial raw FIR building --- .../kotlin/fir/builder/RawFirBuilder.kt | 21 +++++++-- .../testData/partialRawBuilder/local.kt | 15 +++++++ .../testData/partialRawBuilder/local.txt | 3 ++ .../testData/partialRawBuilder/member.kt | 15 +++++++ .../testData/partialRawBuilder/member.txt | 5 +++ .../testData/partialRawBuilder/simple.kt | 11 +++++ .../testData/partialRawBuilder/simple.txt | 3 ++ .../AbstractPartialRawFirBuilderTestCase.kt | 38 ++++++++++++++++ .../builder/AbstractRawFirBuilderTestCase.kt | 2 +- ...PartialRawFirBuilderTestCaseGenerated.java | 45 +++++++++++++++++++ .../fir/resolve/dfa/cfg/CFGNodeRenderer.kt | 4 +- .../org/jetbrains/kotlin/fir/FirRenderer.kt | 26 +++++++++-- .../generators/tests/GenerateCompilerTests.kt | 7 +++ 13 files changed, 186 insertions(+), 9 deletions(-) create mode 100644 compiler/fir/raw-fir/psi2fir/testData/partialRawBuilder/local.kt create mode 100644 compiler/fir/raw-fir/psi2fir/testData/partialRawBuilder/local.txt create mode 100644 compiler/fir/raw-fir/psi2fir/testData/partialRawBuilder/member.kt create mode 100644 compiler/fir/raw-fir/psi2fir/testData/partialRawBuilder/member.txt create mode 100644 compiler/fir/raw-fir/psi2fir/testData/partialRawBuilder/simple.kt create mode 100644 compiler/fir/raw-fir/psi2fir/testData/partialRawBuilder/simple.txt create mode 100644 compiler/fir/raw-fir/psi2fir/tests/org/jetbrains/kotlin/fir/builder/AbstractPartialRawFirBuilderTestCase.kt create mode 100644 compiler/fir/raw-fir/psi2fir/tests/org/jetbrains/kotlin/fir/builder/PartialRawFirBuilderTestCaseGenerated.java diff --git a/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/RawFirBuilder.kt b/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/RawFirBuilder.kt index e8ff2ad7955..8c31c29a866 100644 --- a/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/RawFirBuilder.kt +++ b/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/RawFirBuilder.kt @@ -44,9 +44,7 @@ import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject -import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType -import org.jetbrains.kotlin.psi.psiUtil.hasActualModifier -import org.jetbrains.kotlin.psi.psiUtil.hasExpectModifier +import org.jetbrains.kotlin.psi.psiUtil.* import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.types.expressions.OperatorConventions import org.jetbrains.kotlin.util.OperatorNameConventions @@ -66,6 +64,23 @@ class RawFirBuilder( 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() != null) + } + } + } + return function.accept(Visitor(), Unit) as FirFunction<*> + } + override fun PsiElement.toFirSourceElement(kind: FirFakeSourceElementKind?): FirPsiSourceElement<*> { val actualKind = kind ?: this@RawFirBuilder.context.forcedElementSourceKind ?: FirRealSourceElementKind return this.toFirPsiSourceElement(actualKind) diff --git a/compiler/fir/raw-fir/psi2fir/testData/partialRawBuilder/local.kt b/compiler/fir/raw-fir/psi2fir/testData/partialRawBuilder/local.kt new file mode 100644 index 00000000000..e25795fcc3a --- /dev/null +++ b/compiler/fir/raw-fir/psi2fir/testData/partialRawBuilder/local.kt @@ -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) {} +} \ No newline at end of file diff --git a/compiler/fir/raw-fir/psi2fir/testData/partialRawBuilder/local.txt b/compiler/fir/raw-fir/psi2fir/testData/partialRawBuilder/local.txt new file mode 100644 index 00000000000..20bf6943b21 --- /dev/null +++ b/compiler/fir/raw-fir/psi2fir/testData/partialRawBuilder/local.txt @@ -0,0 +1,3 @@ +local final? fun /bar(): R|kotlin/Unit| { + baz#(i#, x#) +} diff --git a/compiler/fir/raw-fir/psi2fir/testData/partialRawBuilder/member.kt b/compiler/fir/raw-fir/psi2fir/testData/partialRawBuilder/member.kt new file mode 100644 index 00000000000..c9de29c13b9 --- /dev/null +++ b/compiler/fir/raw-fir/psi2fir/testData/partialRawBuilder/member.kt @@ -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() + } + } +} \ No newline at end of file diff --git a/compiler/fir/raw-fir/psi2fir/testData/partialRawBuilder/member.txt b/compiler/fir/raw-fir/psi2fir/testData/partialRawBuilder/member.txt new file mode 100644 index 00000000000..0f92ab18dcf --- /dev/null +++ b/compiler/fir/raw-fir/psi2fir/testData/partialRawBuilder/member.txt @@ -0,0 +1,5 @@ +public? final? fun test/classes/Outer.Inner.foo(): R|kotlin/Unit| { + lval /outer: = Outer#() + lval /inner: = outer#.Inner#() + inner#.bar#() +} diff --git a/compiler/fir/raw-fir/psi2fir/testData/partialRawBuilder/simple.kt b/compiler/fir/raw-fir/psi2fir/testData/partialRawBuilder/simple.kt new file mode 100644 index 00000000000..4ffe7e6468c --- /dev/null +++ b/compiler/fir/raw-fir/psi2fir/testData/partialRawBuilder/simple.kt @@ -0,0 +1,11 @@ +// FUNCTION: foo + +package test + +fun bar(): Int { + return -1 +} + +fun foo(): Int { + return 0 +} \ No newline at end of file diff --git a/compiler/fir/raw-fir/psi2fir/testData/partialRawBuilder/simple.txt b/compiler/fir/raw-fir/psi2fir/testData/partialRawBuilder/simple.txt new file mode 100644 index 00000000000..267e6b89e1d --- /dev/null +++ b/compiler/fir/raw-fir/psi2fir/testData/partialRawBuilder/simple.txt @@ -0,0 +1,3 @@ +public? final? fun test/foo(): Int { + ^foo IntegerLiteral(0) +} diff --git a/compiler/fir/raw-fir/psi2fir/tests/org/jetbrains/kotlin/fir/builder/AbstractPartialRawFirBuilderTestCase.kt b/compiler/fir/raw-fir/psi2fir/tests/org/jetbrains/kotlin/fir/builder/AbstractPartialRawFirBuilderTestCase.kt new file mode 100644 index 00000000000..a4c12cf7d1b --- /dev/null +++ b/compiler/fir/raw-fir/psi2fir/tests/org/jetbrains/kotlin/fir/builder/AbstractPartialRawFirBuilderTestCase.kt @@ -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 { 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: " + } +} \ No newline at end of file diff --git a/compiler/fir/raw-fir/psi2fir/tests/org/jetbrains/kotlin/fir/builder/AbstractRawFirBuilderTestCase.kt b/compiler/fir/raw-fir/psi2fir/tests/org/jetbrains/kotlin/fir/builder/AbstractRawFirBuilderTestCase.kt index 63b4ab833c9..3fe0abd63cb 100644 --- a/compiler/fir/raw-fir/psi2fir/tests/org/jetbrains/kotlin/fir/builder/AbstractRawFirBuilderTestCase.kt +++ b/compiler/fir/raw-fir/psi2fir/tests/org/jetbrains/kotlin/fir/builder/AbstractRawFirBuilderTestCase.kt @@ -60,7 +60,7 @@ abstract class AbstractRawFirBuilderTestCase : KtParsingTestCase( } } - protected fun doRawFirTest(filePath: String) { + protected open fun doRawFirTest(filePath: String) { val file = createKtFile(filePath) val firFile = file.toFirFile(stubMode = false) val firFileDump = StringBuilder().also { FirRenderer(it).visitFile(firFile) }.toString() diff --git a/compiler/fir/raw-fir/psi2fir/tests/org/jetbrains/kotlin/fir/builder/PartialRawFirBuilderTestCaseGenerated.java b/compiler/fir/raw-fir/psi2fir/tests/org/jetbrains/kotlin/fir/builder/PartialRawFirBuilderTestCaseGenerated.java new file mode 100644 index 00000000000..91521a7158a --- /dev/null +++ b/compiler/fir/raw-fir/psi2fir/tests/org/jetbrains/kotlin/fir/builder/PartialRawFirBuilderTestCaseGenerated.java @@ -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"); + } +} diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/CFGNodeRenderer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/CFGNodeRenderer.kt index 3b54e8b5ae0..ad9316c7b3b 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/CFGNodeRenderer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/CFGNodeRenderer.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) { is FirSimpleFunction -> name.asString() diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirRenderer.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirRenderer.kt index f960a0b9456..3ab0eed6d21 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirRenderer.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirRenderer.kt @@ -50,8 +50,14 @@ class FirRenderer(builder: StringBuilder, private val mode: RenderMode = RenderM ) } - abstract class RenderMode(val renderLambdaBodies: Boolean, val renderCallArguments: Boolean) { - object Normal : RenderMode(renderLambdaBodies = true, renderCallArguments = true) + abstract class RenderMode( + 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) @@ -150,8 +156,20 @@ class FirRenderer(builder: StringBuilder, private val mode: RenderMode = RenderM print(".") } when (callableDeclaration) { - is FirSimpleFunction -> print(callableDeclaration.name) - is FirVariable<*> -> print(callableDeclaration.name) + is FirSimpleFunction -> { + 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<*>) { diff --git a/compiler/tests/org/jetbrains/kotlin/generators/tests/GenerateCompilerTests.kt b/compiler/tests/org/jetbrains/kotlin/generators/tests/GenerateCompilerTests.kt index b19ec02d956..a04cfb12418 100644 --- a/compiler/tests/org/jetbrains/kotlin/generators/tests/GenerateCompilerTests.kt +++ b/compiler/tests/org/jetbrains/kotlin/generators/tests/GenerateCompilerTests.kt @@ -22,6 +22,7 @@ import org.jetbrains.kotlin.codegen.defaultConstructor.AbstractDefaultArgumentsR import org.jetbrains.kotlin.codegen.flags.AbstractWriteFlagsTest import org.jetbrains.kotlin.codegen.ir.* import org.jetbrains.kotlin.fir.* +import org.jetbrains.kotlin.fir.builder.AbstractPartialRawFirBuilderTestCase import org.jetbrains.kotlin.fir.builder.AbstractRawFirBuilderTestCase import org.jetbrains.kotlin.fir.java.AbstractFirOldFrontendLightClassesTest import org.jetbrains.kotlin.fir.java.AbstractFirTypeEnhancementTest @@ -544,6 +545,12 @@ fun main(args: Array) { } } + testGroup("compiler/fir/raw-fir/psi2fir/tests", "compiler/fir/raw-fir/psi2fir/testData") { + testClass { + model("partialRawBuilder", testMethod = "doRawFirTest") + } + } + testGroup("compiler/fir/raw-fir/light-tree2fir/tests", "compiler/fir/raw-fir/psi2fir/testData") { testClass { model("rawBuilder")