Add 'parent' to IrDeclaration, initialize it with a hack (for migration)

This commit is contained in:
Dmitry Petrov
2018-01-18 15:37:12 +03:00
parent 24622c0139
commit 9570b64953
9 changed files with 104 additions and 22 deletions
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.psi2ir
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.util.patchDeclarationParents
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi2ir.generators.GeneratorContext
import org.jetbrains.kotlin.psi2ir.generators.ModuleGenerator
@@ -55,5 +56,7 @@ class Psi2IrTranslator(val configuration: Psi2IrConfiguration = Psi2IrConfigurat
insertImplicitCasts(context.builtIns, irElement)
postprocessingSteps.forEach { it.postprocess(context, irElement) }
irElement.patchDeclarationParents()
}
}
@@ -31,6 +31,8 @@ interface IrDeclaration : IrStatement {
val declarationKind: IrDeclarationKind
val origin: IrDeclarationOrigin
val parent: IrDeclarationParent
override fun <D> transform(transformer: IrElementTransformer<D>, data: D): IrStatement =
accept(transformer, data) as IrStatement
}
@@ -16,6 +16,8 @@
package org.jetbrains.kotlin.ir.declarations
interface IrDeclarationContainer {
interface IrDeclarationParent
interface IrDeclarationContainer : IrDeclarationParent {
val declarations: MutableList<IrDeclaration>
}
@@ -24,7 +24,7 @@ import org.jetbrains.kotlin.ir.expressions.IrExpressionBody
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.types.KotlinType
interface IrFunction : IrDeclaration, IrTypeParametersContainer, IrSymbolOwner {
interface IrFunction : IrDeclaration, IrTypeParametersContainer, IrSymbolOwner, IrDeclarationParent {
override val descriptor: FunctionDescriptor
override val symbol: IrFunctionSymbol
@@ -19,9 +19,14 @@ package org.jetbrains.kotlin.ir.declarations.impl
import org.jetbrains.kotlin.ir.IrElementBase
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
import org.jetbrains.kotlin.ir.declarations.IrDeclarationParent
abstract class IrDeclarationBase(
startOffset: Int,
endOffset: Int,
override val origin: IrDeclarationOrigin
) : IrElementBase(startOffset, endOffset), IrDeclaration
) : IrElementBase(startOffset, endOffset),
IrDeclaration {
override lateinit var parent: IrDeclarationParent
}
@@ -31,8 +31,8 @@ import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.types.KotlinType
import java.util.*
inline fun <reified T : IrElement> T.deepCopyOld() =
transform(DeepCopyIrTree(), null) as T
inline fun <reified T : IrElement> T.deepCopyOld(): T =
transform(DeepCopyIrTree(), null).patchDeclarationParents() as T
@Deprecated("Creates unbound symbols")
open class DeepCopyIrTree : IrElementTransformerVoid() {
@@ -32,7 +32,7 @@ import java.util.*
inline fun <reified T : IrElement> T.deepCopyWithSymbols(): T {
val remapper = DeepCopySymbolsRemapper()
acceptVoid(remapper)
return transform(DeepCopyIrTreeWithSymbols(remapper), null) as T
return transform(DeepCopyIrTreeWithSymbols(remapper), null).patchDeclarationParents() as T
}
@@ -0,0 +1,54 @@
/*
* Copyright 2000-2018 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.ir.util
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
import org.jetbrains.kotlin.ir.declarations.IrDeclarationParent
import org.jetbrains.kotlin.ir.declarations.IrPackageFragment
import org.jetbrains.kotlin.ir.declarations.impl.IrDeclarationBase
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.ir.visitors.acceptVoid
import java.util.*
fun <T : IrElement> T.patchDeclarationParents() =
apply {
acceptVoid(PatchDeclarationParentsVisitor())
}
class PatchDeclarationParentsVisitor : IrElementVisitorVoid {
private val declarationParentsStack = ArrayDeque<IrDeclarationParent>()
override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this)
}
override fun visitPackageFragment(declaration: IrPackageFragment) {
declarationParentsStack.push(declaration)
super.visitPackageFragment(declaration)
declarationParentsStack.pop()
}
override fun visitDeclaration(declaration: IrDeclaration) {
patchParent(declaration)
if (declaration is IrDeclarationParent) {
declarationParentsStack.push(declaration)
}
super.visitDeclaration(declaration)
if (declaration is IrDeclarationParent) {
declarationParentsStack.pop()
}
}
private fun patchParent(declaration: IrDeclaration) {
(declaration as IrDeclarationBase).parent = declarationParentsStack.peekFirst()
}
}
@@ -115,6 +115,12 @@ abstract class AbstractIrTextTestCase : AbstractIrGeneratorTestCase() {
errors.add(message)
}
private inline fun require(condition: Boolean, message: () -> String) {
if (!condition) {
errors.add(message())
}
}
fun verifyWithAssert(irFile: IrFile) {
irFile.acceptChildrenVoid(this)
TestCase.assertFalse(errorsAsMessage + "\n\n\n" + irFile.dump(), hasErrors)
@@ -128,8 +134,20 @@ abstract class AbstractIrTextTestCase : AbstractIrGeneratorTestCase() {
if (declaration is IrSymbolOwner) {
declaration.symbol.checkBinding("decl", declaration)
if (declaration.symbol.owner != declaration) {
error("Symbol is not bound to declaration: ${declaration.render()}")
require(declaration.symbol.owner == declaration) {
"Symbol is not bound to declaration: ${declaration.render()}"
}
}
val containingDeclarationDescriptor = declaration.descriptor.containingDeclaration
if (containingDeclarationDescriptor != null) {
val parent = declaration.parent
if (parent is IrDeclaration) {
require(parent.descriptor == containingDeclarationDescriptor) {
"In declaration ${declaration.descriptor}: " +
"Mismatching parent descriptor (${parent.descriptor}) " +
"and containing declaration descriptor ($containingDeclarationDescriptor)"
}
}
}
}
@@ -143,20 +161,18 @@ abstract class AbstractIrTextTestCase : AbstractIrGeneratorTestCase() {
val expectedDispatchReceiver = functionDescriptor.dispatchReceiverParameter
val actualDispatchReceiver = declaration.dispatchReceiverParameter?.descriptor
if (expectedDispatchReceiver != actualDispatchReceiver) {
error(
"$functionDescriptor: Dispatch receiver parameter mismatch: " +
"expected $expectedDispatchReceiver, actual $actualDispatchReceiver"
)
require(expectedDispatchReceiver == actualDispatchReceiver) {
"$functionDescriptor: Dispatch receiver parameter mismatch: " +
"expected $expectedDispatchReceiver, actual $actualDispatchReceiver"
}
val expectedExtensionReceiver = functionDescriptor.extensionReceiverParameter
val actualExtensionReceiver = declaration.extensionReceiverParameter?.descriptor
if (expectedExtensionReceiver != actualExtensionReceiver) {
error(
"$functionDescriptor: Extension receiver parameter mismatch: " +
"expected $expectedExtensionReceiver, actual $actualExtensionReceiver"
)
require(expectedExtensionReceiver == actualExtensionReceiver) {
"$functionDescriptor: Extension receiver parameter mismatch: " +
"expected $expectedExtensionReceiver, actual $actualExtensionReceiver"
}
val declaredValueParameters = declaration.valueParameters.map { it.descriptor }
@@ -165,8 +181,8 @@ abstract class AbstractIrTextTestCase : AbstractIrGeneratorTestCase() {
error("$functionDescriptor: Value parameters mismatch: $declaredValueParameters != $actualValueParameters")
} else {
declaredValueParameters.zip(actualValueParameters).forEach { (declaredValueParameter, actualValueParameter) ->
if (declaredValueParameter != actualValueParameter) {
error("$functionDescriptor: Value parameters mismatch: $declaredValueParameter != $actualValueParameter")
require(declaredValueParameter == actualValueParameter) {
"$functionDescriptor: Value parameters mismatch: $declaredValueParameter != $actualValueParameter"
}
}
}
@@ -220,8 +236,8 @@ abstract class AbstractIrTextTestCase : AbstractIrGeneratorTestCase() {
error("$descriptor: Type parameters mismatch: $declaredTypeParameters != $expectedTypeParameters")
} else {
declaredTypeParameters.zip(expectedTypeParameters).forEach { (declaredTypeParameter, expectedTypeParameter) ->
if (declaredTypeParameter != expectedTypeParameter) {
error("$descriptor: Type parameters mismatch: $declaredTypeParameter != $expectedTypeParameter")
require(declaredTypeParameter == expectedTypeParameter) {
"$descriptor: Type parameters mismatch: $declaredTypeParameter != $expectedTypeParameter"
}
}
}