[FIR IDE] Move and rename RawFirFragmentForLazyBodiesBuilder into Fir Ide module

This commit is contained in:
Igor Yakovlev
2021-05-10 17:09:02 +02:00
committed by TeamCityServer
parent 0569f810cf
commit c5372be267
28 changed files with 168 additions and 98 deletions
@@ -1,147 +0,0 @@
/*
* Copyright 2010-2021 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.psi.PsiElement
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.scopes.FirScopeProvider
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.psi.*
data class RawFirReplacement<T : KtElement>(val from: T, val to: T)
class RawFirFragmentForLazyBodiesBuilder<T : KtElement> private constructor(
session: FirSession,
baseScopeProvider: FirScopeProvider,
private val declarationToBuild: KtDeclaration,
private val replacement: RawFirReplacement<T>? = null
) : RawFirBuilder(session, baseScopeProvider, RawFirBuilderMode.NORMAL) {
private var replacementApplied = false
companion object {
fun elementIsApplicable(element: KtElement) = when (element) {
is KtFile, is KtClassInitializer, is KtClassOrObject, is KtObjectLiteralExpression, is KtTypeAlias,
is KtNamedFunction, is KtLambdaExpression, is KtAnonymousInitializer, is KtProperty, is KtTypeReference,
is KtAnnotationEntry, is KtTypeParameter, is KtTypeProjection, is KtParameter, is KtBlockExpression,
is KtSimpleNameExpression, is KtConstantExpression, is KtStringTemplateExpression, is KtReturnExpression,
is KtTryExpression, is KtIfExpression, is KtWhenExpression, is KtDoWhileExpression, is KtWhileExpression,
is KtForExpression, is KtBreakExpression, is KtContinueExpression, is KtBinaryExpression, is KtBinaryExpressionWithTypeRHS,
is KtIsExpression, is KtUnaryExpression, is KtCallExpression, is KtArrayAccessExpression, is KtQualifiedExpression,
is KtThisExpression, is KtSuperExpression, is KtParenthesizedExpression, is KtLabeledExpression, is KtAnnotatedExpression,
is KtThrowExpression, is KtDestructuringDeclaration, is KtClassLiteralExpression, is KtCallableReferenceExpression,
is KtCollectionLiteralExpression -> true
else -> false
}
fun <T : KtElement> buildWithReplacement(
session: FirSession,
baseScopeProvider: FirScopeProvider,
designation: List<FirDeclaration>,
declarationToBuild: KtDeclaration,
replacement: RawFirReplacement<T>? = null
): FirDeclaration {
if (replacement != null) {
require(elementIsApplicable(replacement.from)) {
"Build with replacement is possible for applicable type but given ${replacement.from::class.simpleName}"
}
require(replacement.from::class == replacement.to::class) {
"Build with replacement is possible for same type in replacements but given\n${replacement.from::class.simpleName} and ${replacement.to::class.simpleName}"
}
}
val builder = RawFirFragmentForLazyBodiesBuilder(session, baseScopeProvider, declarationToBuild, replacement)
builder.context.packageFqName = declarationToBuild.containingKtFile.packageFqName
val result = builder.moveNext(designation.iterator(), containingClass = null)
check(replacement == null || builder.replacementApplied) {
"Replacement requested but was not applied for ${replacement!!.from::class.simpleName}"
}
return result
}
fun build(
session: FirSession,
baseScopeProvider: FirScopeProvider,
designation: List<FirDeclaration>,
rootNonLocalDeclaration: KtDeclaration
): FirDeclaration {
val builder = RawFirFragmentForLazyBodiesBuilder<KtElement>(session, baseScopeProvider, rootNonLocalDeclaration)
builder.context.packageFqName = rootNonLocalDeclaration.containingKtFile.packageFqName
return builder.moveNext(designation.iterator(), containingClass = null)
}
}
private fun KtElement.replaced(): KtElement {
if (replacement == null || replacement.from != this) return this
replacementApplied = true
return replacement.to
}
private inner class VisitorWithReplacement : Visitor() {
override fun convertElement(element: KtElement): FirElement? =
super.convertElement(element.replaced())
override fun convertProperty(
property: KtProperty,
ownerRegularOrAnonymousObjectSymbol: FirClassSymbol<*>?,
ownerRegularClassTypeParametersCount: Int?
): FirProperty {
val replacementProperty = property.replaced()
check(replacementProperty is KtProperty)
return super.convertProperty(
property = replacementProperty,
ownerRegularOrAnonymousObjectSymbol = ownerRegularOrAnonymousObjectSymbol,
ownerRegularClassTypeParametersCount = ownerRegularClassTypeParametersCount
)
}
override fun convertValueParameter(valueParameter: KtParameter, defaultTypeRef: FirTypeRef?): FirValueParameter {
val replacementParameter = valueParameter.replaced()
check(replacementParameter is KtParameter)
return super.convertValueParameter(
valueParameter = replacementParameter,
defaultTypeRef = defaultTypeRef
)
}
}
private fun moveNext(iterator: Iterator<FirDeclaration>, containingClass: FirRegularClass?): FirDeclaration {
if (!iterator.hasNext()) {
val visitor = VisitorWithReplacement()
return when (declarationToBuild) {
is KtProperty -> {
val ownerSymbol = containingClass?.symbol
val ownerTypeArgumentsCount = containingClass?.typeParameters?.size
visitor.convertProperty(declarationToBuild, ownerSymbol, ownerTypeArgumentsCount)
}
else -> visitor.convertElement(declarationToBuild)
} as FirDeclaration
}
val parent = iterator.next()
if (parent !is FirRegularClass) return moveNext(iterator, containingClass = null)
val classOrObject = parent.psi
check(classOrObject is KtClassOrObject)
withChildClassName(classOrObject.nameAsSafeName, false) {
withCapturedTypeParameters {
if (!parent.isInner) context.capturedTypeParameters = context.capturedTypeParameters.clear()
addCapturedTypeParameters(parent.typeParameters.take(classOrObject.typeParameters.size))
registerSelfType(classOrObject.toDelegatedSelfType(parent))
return moveNext(iterator, parent)
}
}
}
private fun PsiElement?.toDelegatedSelfType(firClass: FirRegularClass): FirResolvedTypeRef =
toDelegatedSelfType(firClass.typeParameters, firClass.symbol)
}
@@ -1,15 +0,0 @@
// 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) {}
}
@@ -1,3 +0,0 @@
local final? fun <local>/bar(): R|kotlin/Unit| {
baz#(i#, x#)
}
@@ -1,15 +0,0 @@
// FUNCTION: foo
package test.classes
class Outer {
inner class Inner {
fun bar()
fun foo() {
val outer = Outer()
val inner = outer.Inner()
inner.bar()
}
}
}
@@ -1,5 +0,0 @@
public? final? fun test/classes/Outer.Inner.foo(): R|kotlin/Unit| {
lval <local>/outer: <implicit> = Outer#()
lval <local>/inner: <implicit> = outer#.Inner#()
inner#.bar#()
}
@@ -1,16 +0,0 @@
// 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()
}
}
}
@@ -1,6 +0,0 @@
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#()
}
@@ -1,10 +0,0 @@
// FUNCTION: foo
package test.classes
class Outer<X> {
fun foo() {
val z = object { }
}
}
@@ -1,9 +0,0 @@
public? final? fun test/classes/Outer.foo(): R|kotlin/Unit| {
lval <local>/z: <implicit> = object : R|kotlin/Any| {
private constructor(): R|<anonymous><X>| {
super<R|kotlin/Any|>()
}
}
}
@@ -1,11 +0,0 @@
// FUNCTION: foo
package test
fun bar(): Int {
return -1
}
fun foo(): Int {
return 0
}
@@ -1,3 +0,0 @@
public? final? fun test/foo(): Int {
^foo IntegerLiteral(0)
}
@@ -1,7 +0,0 @@
// PROPERTY: foo
package test
val bar: Int = 10
val foo: Int = 0
@@ -1,2 +0,0 @@
public? final? val test/foo: Int = IntegerLiteral(0)
public? get(): Int
@@ -1,7 +0,0 @@
// PROPERTY: foo
package test
val bar: Int = 10
var foo: Int = 0
@@ -1,3 +0,0 @@
public? final? var test/foo: Int = IntegerLiteral(0)
public? get(): Int
public? set(value: Int): R|kotlin/Unit|
@@ -1,66 +0,0 @@
/*
* Copyright 2010-2021 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.util.KtTestUtil;
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 {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/raw-fir/psi2fir/testData/partialRawBuilder"), Pattern.compile("^(.+)\\.kt$"), null, true);
}
@TestMetadata("localFunction.kt")
public void testLocalFunction() throws Exception {
runTest("compiler/fir/raw-fir/psi2fir/testData/partialRawBuilder/localFunction.kt");
}
@TestMetadata("memberFunction.kt")
public void testMemberFunction() throws Exception {
runTest("compiler/fir/raw-fir/psi2fir/testData/partialRawBuilder/memberFunction.kt");
}
@TestMetadata("memberProperty.kt")
public void testMemberProperty() throws Exception {
runTest("compiler/fir/raw-fir/psi2fir/testData/partialRawBuilder/memberProperty.kt");
}
@TestMetadata("paramemtersCatching.kt")
public void testParamemtersCatching() throws Exception {
runTest("compiler/fir/raw-fir/psi2fir/testData/partialRawBuilder/paramemtersCatching.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");
}
}
@@ -1,109 +0,0 @@
/*
* 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 junit.framework.TestCase
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.FirRenderer
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.psi
import org.jetbrains.kotlin.fir.render
import org.jetbrains.kotlin.fir.session.FirSessionFactory
import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.findDescendantOfType
import org.jetbrains.kotlin.test.InTextDirectivesUtils
import org.jetbrains.kotlin.test.KotlinTestUtils
import java.io.File
abstract class AbstractPartialRawFirBuilderTestCase : AbstractRawFirBuilderTestCase() {
override fun doRawFirTest(filePath: String) {
val fileText = File(filePath).readText()
val functionName = InTextDirectivesUtils.findStringWithPrefixes(fileText, FUNCTION_DIRECTIVE)
val propertyName = InTextDirectivesUtils.findStringWithPrefixes(fileText, PROPERTY_DIRECTIVE)
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 }!! }
}
private fun testPropertyPartialBuilding(filePath: String, nameToFind: String) {
testPartialBuilding(
filePath
) { file -> file.findDescendantOfType<KtProperty> { it.name == nameToFind }!! }
}
private class DesignationBuilder(private val elementToBuild: KtDeclaration) : FirVisitorVoid() {
val designation = mutableListOf<FirDeclaration>()
var originalDeclaration: FirDeclaration? = null
var built = false
override fun visitElement(element: FirElement) {
if (built) return
when (element) {
is FirSimpleFunction, is FirProperty -> {
if (element.psi == elementToBuild) {
originalDeclaration = element as FirDeclaration
built = true
} else {
element.acceptChildren(this)
}
}
is FirRegularClass -> {
designation.add(element)
element.acceptChildren(this)
if (!built) {
designation.removeLast()
}
}
else -> {
element.acceptChildren(this)
}
}
}
}
private fun <T : KtElement> testPartialBuilding(
filePath: String,
findPsiElement: (KtFile) -> T
) {
val file = createKtFile(filePath)
val elementToBuild = findPsiElement(file) as KtDeclaration
val session = FirSessionFactory.createEmptySession()
val firBuilder = RawFirBuilder(session, StubFirScopeProvider)
val original = firBuilder.buildFirFile(file)
val designationBuilder = DesignationBuilder(elementToBuild)
original.accept(designationBuilder)
TestCase.assertTrue(designationBuilder.built)
val firElement = RawFirFragmentForLazyBodiesBuilder.build(
session,
StubFirScopeProvider,
designationBuilder.designation,
elementToBuild
)
val firDump = firElement.render(FirRenderer.RenderMode.WithFqNames)
val expectedPath = filePath.replace(".kt", ".txt")
KotlinTestUtils.assertEqualsToFile(File(expectedPath), firDump)
}
companion object {
private const val FUNCTION_DIRECTIVE = "// FUNCTION: "
private const val PROPERTY_DIRECTIVE = "// PROPERTY: "
}
}