FIR IDE: Implement RawFirBuilder::buildPropertyWithBody, add tests

This commit is contained in:
Roman Golyshev
2020-09-07 15:14:38 +03:00
parent 5f57311015
commit 58965d1e71
15 changed files with 121 additions and 22 deletions
@@ -47,7 +47,6 @@ import org.jetbrains.kotlin.types.expressions.OperatorConventions
import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
import org.jetbrains.kotlin.utils.addToStdlib.runIf import org.jetbrains.kotlin.utils.addToStdlib.runIf
import java.util.*
class RawFirBuilder( class RawFirBuilder(
session: FirSession, val baseScopeProvider: FirScopeProvider, val stubMode: Boolean session: FirSession, val baseScopeProvider: FirScopeProvider, val stubMode: Boolean
@@ -63,7 +62,19 @@ class RawFirBuilder(
fun buildFunctionWithBody(function: KtNamedFunction): FirFunction<*> { fun buildFunctionWithBody(function: KtNamedFunction): FirFunction<*> {
assert(!stubMode) { "Building FIR function with body isn't supported in stub mode" } assert(!stubMode) { "Building FIR function with body isn't supported in stub mode" }
val parentsUpToFile = function.parents setupContextForPosition(function)
return function.accept(Visitor(), Unit) as FirFunction<*>
}
fun buildPropertyWithBody(property: KtProperty): FirProperty {
require(!property.isLocal) { "Should not be used to build local properties (variables)" }
assert(!stubMode) { "Building FIR function with body isn't supported in stub mode" }
setupContextForPosition(property)
return property.accept(Visitor(), Unit) as FirProperty
}
private fun setupContextForPosition(position: KtElement) {
val parentsUpToFile = position.parents
for (parent in parentsUpToFile.toList().asReversed()) { for (parent in parentsUpToFile.toList().asReversed()) {
when (parent) { when (parent) {
is KtFile -> { is KtFile -> {
@@ -75,7 +86,6 @@ class RawFirBuilder(
} }
} }
} }
return function.accept(Visitor(), Unit) as FirFunction<*>
} }
override fun PsiElement.toFirSourceElement(kind: FirFakeSourceElementKind?): FirPsiSourceElement<*> { override fun PsiElement.toFirSourceElement(kind: FirFakeSourceElementKind?): FirPsiSourceElement<*> {
@@ -0,0 +1,16 @@
// PROPERTY: foo
package test.classes
class Outer {
inner class Inner {
fun bar(): Int
val foo: Int
get() {
val outer = Outer()
val inner = outer.Inner()
return inner.bar()
}
}
}
@@ -0,0 +1,6 @@
public? final? val test/classes/Outer.Inner.foo: Int
public? get(): Int {
lval <local>/outer: <implicit> = Outer#()
lval <local>/inner: <implicit> = outer#.Inner#()
^ inner#.bar#()
}
@@ -0,0 +1,7 @@
// PROPERTY: foo
package test
val bar: Int = 10
val foo: Int = 0
@@ -0,0 +1,2 @@
public? final? val test/foo: Int = IntegerLiteral(0)
public? get(): Int
@@ -0,0 +1,7 @@
// PROPERTY: foo
package test
val bar: Int = 10
var foo: Int = 0
@@ -0,0 +1,3 @@
public? final? var test/foo: Int = IntegerLiteral(0)
public? get(): Int
public? set(value: Int): R|kotlin/Unit|
@@ -5,36 +5,69 @@
package org.jetbrains.kotlin.fir.builder package org.jetbrains.kotlin.fir.builder
import junit.framework.TestCase
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.FirRenderer import org.jetbrains.kotlin.fir.FirRenderer
import org.jetbrains.kotlin.fir.render import org.jetbrains.kotlin.fir.render
import org.jetbrains.kotlin.fir.session.FirSessionFactory import org.jetbrains.kotlin.fir.session.FirSessionFactory
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtNamedFunction import org.jetbrains.kotlin.psi.KtNamedFunction
import org.jetbrains.kotlin.psi.KtProperty
import org.jetbrains.kotlin.psi.psiUtil.findDescendantOfType import org.jetbrains.kotlin.psi.psiUtil.findDescendantOfType
import org.jetbrains.kotlin.test.InTextDirectivesUtils
import org.jetbrains.kotlin.test.KotlinTestUtils import org.jetbrains.kotlin.test.KotlinTestUtils
import java.io.File import java.io.File
abstract class AbstractPartialRawFirBuilderTestCase : AbstractRawFirBuilderTestCase() { abstract class AbstractPartialRawFirBuilderTestCase : AbstractRawFirBuilderTestCase() {
override fun doRawFirTest(filePath: String) { override fun doRawFirTest(filePath: String) {
val nameToFind = File(filePath).useLines { val fileText = File(filePath).readText()
it.first().run { val functionName = InTextDirectivesUtils.findStringWithPrefixes(fileText, FUNCTION_DIRECTIVE)
assert(startsWith(Companion.prefix)) val propertyName = InTextDirectivesUtils.findStringWithPrefixes(fileText, PROPERTY_DIRECTIVE)
drop(Companion.prefix.length)
} when {
functionName != null -> testFunctionPartialBuilding(filePath, functionName)
propertyName != null -> testPropertyPartialBuilding(filePath, propertyName)
else -> fail("No '$FUNCTION_DIRECTIVE' or '$PROPERTY_DIRECTIVE' directives found!")
} }
}
private fun testFunctionPartialBuilding(filePath: String, nameToFind: String) {
testPartialBuilding(
filePath,
{ file -> file.findDescendantOfType<KtNamedFunction> { it.name == nameToFind }!! },
RawFirBuilder::buildFunctionWithBody
)
}
private fun testPropertyPartialBuilding(filePath: String, nameToFind: String) {
testPartialBuilding(
filePath,
{ file -> file.findDescendantOfType<KtProperty> { it.name == nameToFind }!! },
RawFirBuilder::buildPropertyWithBody
)
}
private fun <T : KtElement> testPartialBuilding(
filePath: String,
findPsiElement: (KtFile) -> T,
buildFirElement: (RawFirBuilder, T) -> FirElement
) {
val file = createKtFile(filePath) val file = createKtFile(filePath)
val functionToBuild = file.findDescendantOfType<KtNamedFunction> { it.name == nameToFind }!! val elementToBuild = findPsiElement(file)
val session = FirSessionFactory.createEmptySession() val session = FirSessionFactory.createEmptySession()
val firFunction = RawFirBuilder(session, StubFirScopeProvider, false) val firElement = buildFirElement(RawFirBuilder(session, StubFirScopeProvider, false), elementToBuild)
.buildFunctionWithBody(functionToBuild)
val firDump = firFunction.render(FirRenderer.RenderMode.WithFqNames) val firDump = firElement.render(FirRenderer.RenderMode.WithFqNames)
val expectedPath = filePath.replace(".kt", ".txt") val expectedPath = filePath.replace(".kt", ".txt")
KotlinTestUtils.assertEqualsToFile(File(expectedPath), firDump) KotlinTestUtils.assertEqualsToFile(File(expectedPath), firDump)
} }
companion object { companion object {
private const val prefix = "// FUNCTION: " private const val FUNCTION_DIRECTIVE = "// FUNCTION: "
private const val PROPERTY_DIRECTIVE = "// PROPERTY: "
} }
} }
@@ -28,18 +28,33 @@ public class PartialRawFirBuilderTestCaseGenerated extends AbstractPartialRawFir
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/raw-fir/psi2fir/testData/partialRawBuilder"), Pattern.compile("^(.+)\\.kt$"), null, true); KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/raw-fir/psi2fir/testData/partialRawBuilder"), Pattern.compile("^(.+)\\.kt$"), null, true);
} }
@TestMetadata("local.kt") @TestMetadata("localFunction.kt")
public void testLocal() throws Exception { public void testLocalFunction() throws Exception {
runTest("compiler/fir/raw-fir/psi2fir/testData/partialRawBuilder/local.kt"); runTest("compiler/fir/raw-fir/psi2fir/testData/partialRawBuilder/localFunction.kt");
} }
@TestMetadata("member.kt") @TestMetadata("memberFunction.kt")
public void testMember() throws Exception { public void testMemberFunction() throws Exception {
runTest("compiler/fir/raw-fir/psi2fir/testData/partialRawBuilder/member.kt"); runTest("compiler/fir/raw-fir/psi2fir/testData/partialRawBuilder/memberFunction.kt");
} }
@TestMetadata("simple.kt") @TestMetadata("memberProperty.kt")
public void testSimple() throws Exception { public void testMemberProperty() throws Exception {
runTest("compiler/fir/raw-fir/psi2fir/testData/partialRawBuilder/simple.kt"); runTest("compiler/fir/raw-fir/psi2fir/testData/partialRawBuilder/memberProperty.kt");
}
@TestMetadata("simpleFunction.kt")
public void testSimpleFunction() throws Exception {
runTest("compiler/fir/raw-fir/psi2fir/testData/partialRawBuilder/simpleFunction.kt");
}
@TestMetadata("simpleVal.kt")
public void testSimpleVal() throws Exception {
runTest("compiler/fir/raw-fir/psi2fir/testData/partialRawBuilder/simpleVal.kt");
}
@TestMetadata("simpleVar.kt")
public void testSimpleVar() throws Exception {
runTest("compiler/fir/raw-fir/psi2fir/testData/partialRawBuilder/simpleVar.kt");
} }
} }