- IR expressions for calls & references
- first calls "parsed"
This commit is contained in:
committed by
Dmitry Petrov
parent
c09ba962c4
commit
c93666f6f1
@@ -16,37 +16,61 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.psi2ir
|
package org.jetbrains.kotlin.psi2ir
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.*
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
||||||
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.callUtil.isSafeCall
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall
|
||||||
import org.jetbrains.kotlin.resolve.constants.IntValue
|
import org.jetbrains.kotlin.resolve.constants.IntValue
|
||||||
import org.jetbrains.kotlin.resolve.constants.StringValue
|
import org.jetbrains.kotlin.resolve.constants.StringValue
|
||||||
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator
|
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator
|
||||||
|
import org.jetbrains.kotlin.resolve.scopes.receivers.*
|
||||||
|
|
||||||
class IrExpressionGenerator(
|
class IrExpressionGenerator(
|
||||||
override val context: IrGeneratorContext,
|
override val context: IrGeneratorContext,
|
||||||
val declarationFactory: IrDeclarationFactory
|
val declarationFactory: IrDeclarationFactory
|
||||||
) : KtVisitor<IrExpressionBase, Nothing?>(), IrGenerator {
|
) : KtVisitor<IrExpression, Nothing?>(), IrGenerator {
|
||||||
fun generateExpression(ktExpression: KtExpression) = ktExpression.generate()
|
fun generateExpression(ktExpression: KtExpression) = ktExpression.generate()
|
||||||
|
|
||||||
private fun KtElement.generate(): IrExpressionBase = accept(this@IrExpressionGenerator, null)
|
private fun KtElement.generate(): IrExpression =
|
||||||
private fun KtExpression.type() = getType(this) ?: TODO("no type for expression")
|
accept(this@IrExpressionGenerator, null).applySmartCast(this)
|
||||||
|
|
||||||
override fun visitExpression(expression: KtExpression, data: Nothing?): IrExpressionBase =
|
private fun KtExpression.type() =
|
||||||
IrDummyExpression(expression.startOffset, expression.endOffset, expression.type())
|
getType(this) ?: TODO("no type for expression")
|
||||||
|
|
||||||
override fun visitBlockExpression(expression: KtBlockExpression, data: Nothing?): IrExpressionBase {
|
private fun IrExpression.applySmartCast(ktElement: KtElement): IrExpression {
|
||||||
val irBlock = IrBlockExpressionImpl(expression.startOffset, expression.endOffset, expression.type())
|
if (ktElement is KtExpression) {
|
||||||
expression.statements.forEach { irBlock.childExpressions.add(it.generate()) }
|
val smartCastType = get(BindingContext.SMARTCAST, ktElement)
|
||||||
|
if (smartCastType != null) {
|
||||||
|
return IrTypeOperatorExpressionImpl(
|
||||||
|
ktElement.startOffset, ktElement.endOffset, smartCastType,
|
||||||
|
IrTypeOperator.SMART_AS, smartCastType
|
||||||
|
).apply { childExpression = this@applySmartCast }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitExpression(expression: KtExpression, data: Nothing?): IrExpression =
|
||||||
|
IrDummyExpression(expression.startOffset, expression.endOffset, expression.type(), expression.javaClass.simpleName)
|
||||||
|
|
||||||
|
override fun visitBlockExpression(expression: KtBlockExpression, data: Nothing?): IrExpression {
|
||||||
|
val irBlock = IrBlockExpressionImpl(expression.startOffset, expression.endOffset, expression.type(), false)
|
||||||
|
expression.statements.forEach { irBlock.addChildExpression(it.generate()) }
|
||||||
return irBlock
|
return irBlock
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitReturnExpression(expression: KtReturnExpression, data: Nothing?): IrExpressionBase =
|
override fun visitReturnExpression(expression: KtReturnExpression, data: Nothing?): IrExpression =
|
||||||
IrReturnExpressionImpl(expression.startOffset, expression.endOffset, expression.type())
|
IrReturnExpressionImpl(expression.startOffset, expression.endOffset, expression.type())
|
||||||
.apply { this.childExpression = expression.returnedExpression?.generate() }
|
.apply { this.childExpression = expression.returnedExpression?.generate() }
|
||||||
|
|
||||||
override fun visitConstantExpression(expression: KtConstantExpression, data: Nothing?): IrExpressionBase {
|
override fun visitConstantExpression(expression: KtConstantExpression, data: Nothing?): IrExpression {
|
||||||
val compileTimeConstant = ConstantExpressionEvaluator.getConstant(expression, context.bindingContext)
|
val compileTimeConstant = ConstantExpressionEvaluator.getConstant(expression, context.bindingContext)
|
||||||
?: error("KtConstantExpression was not evaluated: ${expression.text}")
|
?: error("KtConstantExpression was not evaluated: ${expression.text}")
|
||||||
val constantValue = compileTimeConstant.toConstantValue(expression.type())
|
val constantValue = compileTimeConstant.toConstantValue(expression.type())
|
||||||
@@ -62,7 +86,7 @@ class IrExpressionGenerator(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitStringTemplateExpression(expression: KtStringTemplateExpression, data: Nothing?): IrExpressionBase {
|
override fun visitStringTemplateExpression(expression: KtStringTemplateExpression, data: Nothing?): IrExpression {
|
||||||
if (expression.entries.size == 1 && expression.entries[0] is KtLiteralStringTemplateEntry) {
|
if (expression.entries.size == 1 && expression.entries[0] is KtLiteralStringTemplateEntry) {
|
||||||
return expression.entries[0].generate()
|
return expression.entries[0].generate()
|
||||||
}
|
}
|
||||||
@@ -72,6 +96,110 @@ class IrExpressionGenerator(
|
|||||||
return irStringTemplate
|
return irStringTemplate
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitLiteralStringTemplateEntry(entry: KtLiteralStringTemplateEntry, data: Nothing?): IrExpressionBase =
|
override fun visitLiteralStringTemplateEntry(entry: KtLiteralStringTemplateEntry, data: Nothing?): IrExpression =
|
||||||
IrLiteralExpressionImpl.string(entry.startOffset, entry.endOffset, context.builtIns.stringType, entry.text)
|
IrLiteralExpressionImpl.string(entry.startOffset, entry.endOffset, context.builtIns.stringType, entry.text)
|
||||||
|
|
||||||
|
override fun visitSimpleNameExpression(expression: KtSimpleNameExpression, data: Nothing?): IrExpression {
|
||||||
|
val resolvedCall = getResolvedCall(expression)
|
||||||
|
|
||||||
|
if (resolvedCall is VariableAsFunctionResolvedCall) {
|
||||||
|
TODO("Unexpected VariableAsFunctionResolvedCall")
|
||||||
|
}
|
||||||
|
|
||||||
|
val descriptor = resolvedCall?.resultingDescriptor ?: get(BindingContext.REFERENCE_TARGET, expression)
|
||||||
|
|
||||||
|
return when (descriptor) {
|
||||||
|
is ClassDescriptor ->
|
||||||
|
IrSingletonReferenceImpl(expression.startOffset, expression.endOffset, expression.type(),
|
||||||
|
descriptor.singletonDescriptor() ?: TODO("Unsupported class as value: ${descriptor.name}"))
|
||||||
|
is PropertyDescriptor -> {
|
||||||
|
generateCall(
|
||||||
|
expression,
|
||||||
|
resolvedCall ?: TODO("Property, no resolved call: ${descriptor.name}"),
|
||||||
|
IrCallableOperator.PROPERTY_GET
|
||||||
|
)
|
||||||
|
}
|
||||||
|
is VariableDescriptor ->
|
||||||
|
IrVariableReferenceImpl(expression.startOffset, expression.endOffset, expression.type(), descriptor)
|
||||||
|
else ->
|
||||||
|
IrDummyExpression(expression.startOffset, expression.endOffset, expression.type(),
|
||||||
|
expression.getReferencedName() +
|
||||||
|
": ${descriptor?.name} ${descriptor?.javaClass?.simpleName}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitCallExpression(expression: KtCallExpression, data: Nothing?): IrExpression {
|
||||||
|
val resolvedCall = getResolvedCall(expression) ?: TODO("No resolved call for call expression")
|
||||||
|
|
||||||
|
if (resolvedCall is VariableAsFunctionResolvedCall) {
|
||||||
|
TODO("VariableAsFunctionResolvedCall = variable call + invoke call")
|
||||||
|
}
|
||||||
|
|
||||||
|
return generateCall(expression, resolvedCall, null, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun generateCall(
|
||||||
|
ktExpression: KtExpression,
|
||||||
|
resolvedCall: ResolvedCall<out CallableDescriptor>,
|
||||||
|
operator: IrCallableOperator?,
|
||||||
|
superQualifier: ClassDescriptor? = null
|
||||||
|
): IrExpression =
|
||||||
|
IrCallExpressionImpl(
|
||||||
|
ktExpression.startOffset, ktExpression.endOffset, ktExpression.type(),
|
||||||
|
resolvedCall.resultingDescriptor, resolvedCall.call.isSafeCall(), operator, superQualifier
|
||||||
|
).apply {
|
||||||
|
dispatchReceiver = generateReceiver(ktExpression, resolvedCall.dispatchReceiver)
|
||||||
|
extensionReceiver = generateReceiver(ktExpression, resolvedCall.extensionReceiver)
|
||||||
|
|
||||||
|
val valueParameters = resolvedCall.resultingDescriptor.valueParameters
|
||||||
|
val valueArguments = resolvedCall.valueArgumentsByIndex ?: TODO("null for value arguments: ${ktExpression.text}")
|
||||||
|
for (index in valueArguments.indices) {
|
||||||
|
val valueArgument = valueArguments[index]
|
||||||
|
val valueParameter = valueParameters[index]
|
||||||
|
putValueArgument(valueParameter, generateValueArgument(valueParameter, valueArgument))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun generateReceiver(ktExpression: KtExpression, receiver: ReceiverValue?): IrExpression? =
|
||||||
|
when (receiver) {
|
||||||
|
is ImplicitClassReceiver ->
|
||||||
|
IrThisExpressionImpl(ktExpression.startOffset, ktExpression.startOffset, receiver.type, receiver.classDescriptor)
|
||||||
|
is ThisClassReceiver ->
|
||||||
|
(receiver as? ExpressionReceiver)?.expression?.let { receiverExpression ->
|
||||||
|
IrThisExpressionImpl(receiverExpression.startOffset, receiverExpression.endOffset, receiver.type, receiver.classDescriptor)
|
||||||
|
} ?: TODO("Non-implicit ThisClassReceiver should be an expression receiver")
|
||||||
|
is ExpressionReceiver ->
|
||||||
|
receiver.expression.generate()
|
||||||
|
is ClassValueReceiver ->
|
||||||
|
IrSingletonReferenceImpl(receiver.expression.startOffset, receiver.expression.endOffset, receiver.type,
|
||||||
|
receiver.classQualifier.descriptor)
|
||||||
|
is ExtensionReceiver ->
|
||||||
|
IrExtensionReceiverReferenceImpl(ktExpression.startOffset, ktExpression.startOffset, receiver.type,
|
||||||
|
receiver.declarationDescriptor.extensionReceiverParameter!!)
|
||||||
|
null ->
|
||||||
|
null
|
||||||
|
else ->
|
||||||
|
IrDummyExpression(ktExpression.startOffset, ktExpression.endOffset, receiver.type,
|
||||||
|
"Receiver: ${receiver.javaClass.simpleName}")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun generateValueArgument(valueParameter: ValueParameterDescriptor, valueArgument: ResolvedValueArgument): IrExpression? {
|
||||||
|
if (valueParameter.varargElementType == null) {
|
||||||
|
assert(valueArgument.arguments.size == 1) { "Single value argument expected for a non-vararg parameter" }
|
||||||
|
return valueArgument.arguments.single().getArgumentExpression()!!.generate()
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
TODO("vararg")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun ClassDescriptor.singletonDescriptor(): ClassDescriptor? =
|
||||||
|
if (DescriptorUtils.isObject(this) || DescriptorUtils.isEnumEntry(this))
|
||||||
|
this
|
||||||
|
else
|
||||||
|
companionObjectDescriptor
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,10 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.psi2ir
|
package org.jetbrains.kotlin.psi2ir
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||||
import org.jetbrains.kotlin.psi.KtExpression
|
import org.jetbrains.kotlin.psi.KtExpression
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
import org.jetbrains.kotlin.util.slicedMap.ReadOnlySlice
|
import org.jetbrains.kotlin.util.slicedMap.ReadOnlySlice
|
||||||
|
|
||||||
@@ -35,3 +38,6 @@ inline fun <K, V : Any> IrGenerator.getOrFail(slice: ReadOnlySlice<K, V>, key: K
|
|||||||
|
|
||||||
inline fun <K, V : Any> IrGenerator.getOrElse(slice: ReadOnlySlice<K, V>, key: K, otherwise: (K) -> V): V =
|
inline fun <K, V : Any> IrGenerator.getOrElse(slice: ReadOnlySlice<K, V>, key: K, otherwise: (K) -> V): V =
|
||||||
context.bindingContext[slice, key] ?: otherwise(key)
|
context.bindingContext[slice, key] ?: otherwise(key)
|
||||||
|
|
||||||
|
fun IrGenerator.getResolvedCall(key: KtExpression): ResolvedCall<out CallableDescriptor>? =
|
||||||
|
key.getResolvedCall(context.bindingContext)
|
||||||
@@ -20,12 +20,18 @@ import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
|||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
|
||||||
|
|
||||||
interface IrBlockExpression : IrCompoundExpressionN
|
interface IrBlockExpression : IrCompoundExpressionN {
|
||||||
|
val hasResult: Boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IrBlockExpression.getResultExpression() =
|
||||||
|
if (hasResult) childExpressions.lastOrNull() else null
|
||||||
|
|
||||||
class IrBlockExpressionImpl(
|
class IrBlockExpressionImpl(
|
||||||
startOffset: Int,
|
startOffset: Int,
|
||||||
endOffset: Int,
|
endOffset: Int,
|
||||||
type: KotlinType
|
type: KotlinType,
|
||||||
|
override val hasResult: Boolean
|
||||||
) : IrCompoundExpressionNBase(startOffset, endOffset, type), IrBlockExpression {
|
) : IrCompoundExpressionNBase(startOffset, endOffset, type), IrBlockExpression {
|
||||||
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
|
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
|
||||||
visitor.visitBlockExpression(this, data)
|
visitor.visitBlockExpression(this, data)
|
||||||
|
|||||||
@@ -0,0 +1,142 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2016 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.ir.expressions
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||||
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
|
||||||
|
interface IrCallExpression : IrCompoundExpression {
|
||||||
|
val superQualifier: ClassDescriptor?
|
||||||
|
val operator: IrCallableOperator?
|
||||||
|
val isSafe: Boolean
|
||||||
|
val callee: CallableDescriptor
|
||||||
|
var dispatchReceiver: IrExpression?
|
||||||
|
var extensionReceiver: IrExpression?
|
||||||
|
|
||||||
|
fun getValueArgument(valueParameterDescriptor: ValueParameterDescriptor): IrExpression?
|
||||||
|
fun putValueArgument(valueParameterDescriptor: ValueParameterDescriptor, valueArgument: IrExpression?)
|
||||||
|
fun removeValueArgument(valueParameterDescriptor: ValueParameterDescriptor)
|
||||||
|
|
||||||
|
fun <D> acceptValueArguments(visitor: IrElementVisitor<Unit, D>, data: D)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IrCallExpression.getMappedValueArguments(): List<IrExpression?> =
|
||||||
|
callee.valueParameters.mapNotNull { getValueArgument(it) }
|
||||||
|
|
||||||
|
abstract class IrCallExpressionBase(
|
||||||
|
startOffset: Int,
|
||||||
|
endOffset: Int,
|
||||||
|
type: KotlinType,
|
||||||
|
override final val callee: CallableDescriptor,
|
||||||
|
override val isSafe: Boolean,
|
||||||
|
override val operator: IrCallableOperator?,
|
||||||
|
override val superQualifier: ClassDescriptor?
|
||||||
|
) : IrExpressionBase(startOffset, endOffset, type), IrCallExpression {
|
||||||
|
private val argumentsByParameterIndex =
|
||||||
|
kotlin.arrayOfNulls<IrExpression>(callee.valueParameters.size)
|
||||||
|
|
||||||
|
override var dispatchReceiver: IrExpression? = null
|
||||||
|
set(newReceiver) {
|
||||||
|
field?.detach()
|
||||||
|
field = newReceiver
|
||||||
|
newReceiver?.setTreeLocation(this, DISPATCH_RECEIVER_INDEX)
|
||||||
|
}
|
||||||
|
|
||||||
|
override var extensionReceiver: IrExpression? = null
|
||||||
|
set(newReceiver) {
|
||||||
|
field?.detach()
|
||||||
|
field = newReceiver
|
||||||
|
newReceiver?.setTreeLocation(this, EXTENSION_RECEIVER_INDEX)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getValueArgument(valueParameterDescriptor: ValueParameterDescriptor): IrExpression? =
|
||||||
|
argumentsByParameterIndex[valueParameterDescriptor.index]
|
||||||
|
|
||||||
|
override fun putValueArgument(valueParameterDescriptor: ValueParameterDescriptor, valueArgument: IrExpression?) {
|
||||||
|
putValueArgument(valueParameterDescriptor.index, valueArgument)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun putValueArgument(index: Int, valueArgument: IrExpression?) {
|
||||||
|
argumentsByParameterIndex[index]?.detach()
|
||||||
|
argumentsByParameterIndex[index] = valueArgument
|
||||||
|
valueArgument?.setTreeLocation(this, index)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun removeValueArgument(valueParameterDescriptor: ValueParameterDescriptor) {
|
||||||
|
argumentsByParameterIndex[valueParameterDescriptor.index]?.detach()
|
||||||
|
argumentsByParameterIndex[valueParameterDescriptor.index] = null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getChildExpression(index: Int): IrExpression? =
|
||||||
|
when (index) {
|
||||||
|
DISPATCH_RECEIVER_INDEX ->
|
||||||
|
dispatchReceiver
|
||||||
|
EXTENSION_RECEIVER_INDEX ->
|
||||||
|
extensionReceiver
|
||||||
|
else ->
|
||||||
|
argumentsByParameterIndex.getOrNull(index)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun replaceChildExpression(oldChild: IrExpression, newChild: IrExpression) {
|
||||||
|
validateChild(oldChild)
|
||||||
|
when (oldChild.index) {
|
||||||
|
DISPATCH_RECEIVER_INDEX ->
|
||||||
|
dispatchReceiver = newChild
|
||||||
|
EXTENSION_RECEIVER_INDEX ->
|
||||||
|
extensionReceiver = newChild
|
||||||
|
else ->
|
||||||
|
putValueArgument(oldChild.index, newChild)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun <D> acceptValueArguments(visitor: IrElementVisitor<Unit, D>, data: D) {
|
||||||
|
for (valueArgument in argumentsByParameterIndex) {
|
||||||
|
valueArgument?.let { it.accept(visitor, data) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun <D> acceptChildExpressions(visitor: IrElementVisitor<Unit, D>, data: D) {
|
||||||
|
dispatchReceiver?.accept(visitor, data)
|
||||||
|
extensionReceiver?.accept(visitor, data)
|
||||||
|
acceptValueArguments(visitor, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
|
||||||
|
acceptChildExpressions(visitor, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val DISPATCH_RECEIVER_INDEX = -1
|
||||||
|
const val EXTENSION_RECEIVER_INDEX = -2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class IrCallExpressionImpl(
|
||||||
|
startOffset: Int,
|
||||||
|
endOffset: Int,
|
||||||
|
type: KotlinType,
|
||||||
|
callee: CallableDescriptor,
|
||||||
|
isSafe: Boolean,
|
||||||
|
operator: IrCallableOperator? = null,
|
||||||
|
superQualifier: ClassDescriptor? = null
|
||||||
|
) : IrCallExpressionBase(startOffset, endOffset, type, callee, isSafe, operator, superQualifier), IrCallExpression {
|
||||||
|
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
|
||||||
|
visitor.visitCallExpression(this, data)
|
||||||
|
}
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2016 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.ir.expressions
|
||||||
|
|
||||||
|
enum class IrCallableOperator {
|
||||||
|
PROPERTY_GET,
|
||||||
|
PROPERTY_SET,
|
||||||
|
INVOKE,
|
||||||
|
INVOKE_EXTENSION,
|
||||||
|
PLUSPLUS,
|
||||||
|
MINUSMINUS,
|
||||||
|
UMINUS,
|
||||||
|
EXCL,
|
||||||
|
LT,
|
||||||
|
GT,
|
||||||
|
LTEQ,
|
||||||
|
GTEQ,
|
||||||
|
EQEQ,
|
||||||
|
EQEQEQ,
|
||||||
|
EXCLEQ,
|
||||||
|
EXCLEQEQ,
|
||||||
|
IN,
|
||||||
|
NOT_IN,
|
||||||
|
ANDAND,
|
||||||
|
OROR,
|
||||||
|
RANGE,
|
||||||
|
PLUS,
|
||||||
|
MINUS,
|
||||||
|
MUL,
|
||||||
|
DIV,
|
||||||
|
MOD,
|
||||||
|
PLUSEQ,
|
||||||
|
MINUSEQ,
|
||||||
|
MULEQ,
|
||||||
|
DIVEQ,
|
||||||
|
MODEQ;
|
||||||
|
}
|
||||||
|
|
||||||
|
fun IrCallableOperator.isCompoundAssignment(): Boolean =
|
||||||
|
this >= IrCallableOperator.PLUSEQ && this <= IrCallableOperator.MODEQ
|
||||||
|
|
||||||
|
fun IrCallableOperator.hasCompoundAssignmentDual(): Boolean =
|
||||||
|
this >= IrCallableOperator.PLUS && this <= IrCallableOperator.MOD
|
||||||
|
|
||||||
|
fun IrCallableOperator.toDualOperator(): IrCallableOperator =
|
||||||
|
when {
|
||||||
|
isCompoundAssignment() ->
|
||||||
|
IrCallableOperator.values()[this.ordinal - IrCallableOperator.PLUSEQ.ordinal + IrCallableOperator.PLUS.ordinal]
|
||||||
|
hasCompoundAssignmentDual() ->
|
||||||
|
IrCallableOperator.values()[this.ordinal - IrCallableOperator.PLUS.ordinal + IrCallableOperator.PLUSEQ.ordinal]
|
||||||
|
else ->
|
||||||
|
throw UnsupportedOperationException("Operator $this is not a compound assignment")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2016 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.ir.expressions
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||||
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
|
||||||
|
|
||||||
|
interface IrDeclarationReference : IrExpression {
|
||||||
|
val descriptor: DeclarationDescriptor
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IrVariableReference : IrDeclarationReference {
|
||||||
|
override val descriptor: VariableDescriptor
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IrSingletonReference : IrDeclarationReference {
|
||||||
|
override val descriptor: ClassDescriptor
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IrExtensionReceiverReference : IrDeclarationReference {
|
||||||
|
override val descriptor: CallableDescriptor
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class IrDeclarationReferenceBase<out D : DeclarationDescriptor>(
|
||||||
|
startOffset: Int,
|
||||||
|
endOffset: Int,
|
||||||
|
type: KotlinType,
|
||||||
|
override val descriptor: D
|
||||||
|
) : IrTerminalExpressionBase(startOffset, endOffset, type), IrDeclarationReference
|
||||||
|
|
||||||
|
class IrVariableReferenceImpl(
|
||||||
|
startOffset: Int,
|
||||||
|
endOffset: Int,
|
||||||
|
type: KotlinType,
|
||||||
|
descriptor: VariableDescriptor
|
||||||
|
) : IrDeclarationReferenceBase<VariableDescriptor>(startOffset, endOffset, type, descriptor), IrVariableReference {
|
||||||
|
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
|
||||||
|
visitor.visitVariableReference(this, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
class IrSingletonReferenceImpl(
|
||||||
|
startOffset: Int,
|
||||||
|
endOffset: Int,
|
||||||
|
type: KotlinType,
|
||||||
|
descriptor: ClassDescriptor
|
||||||
|
) : IrDeclarationReferenceBase<ClassDescriptor>(startOffset, endOffset, type, descriptor), IrSingletonReference {
|
||||||
|
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
|
||||||
|
visitor.visitSingletonReference(this, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class IrExtensionReceiverReferenceImpl(
|
||||||
|
startOffset: Int,
|
||||||
|
endOffset: Int,
|
||||||
|
type: KotlinType,
|
||||||
|
override val descriptor: CallableDescriptor
|
||||||
|
) : IrTerminalExpressionBase(startOffset, endOffset, type), IrExtensionReceiverReference {
|
||||||
|
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R {
|
||||||
|
return visitor.visitExtensionReceiverReference(this, data)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -22,10 +22,11 @@ import org.jetbrains.kotlin.types.KotlinType
|
|||||||
class IrDummyExpression(
|
class IrDummyExpression(
|
||||||
startOffset: Int,
|
startOffset: Int,
|
||||||
endOffset: Int,
|
endOffset: Int,
|
||||||
type: KotlinType
|
type: KotlinType,
|
||||||
|
val description: String
|
||||||
) : IrExpressionBase(startOffset, endOffset, type) {
|
) : IrExpressionBase(startOffset, endOffset, type) {
|
||||||
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
|
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
|
||||||
visitor.visitElement(this, data)
|
visitor.visitDummyExpression(this, data)
|
||||||
|
|
||||||
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
|
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
|
||||||
// No children
|
// No children
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.ir.expressions
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.ir.IrElement
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
import org.jetbrains.kotlin.ir.IrElementBase
|
import org.jetbrains.kotlin.ir.IrElementBase
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
|
||||||
|
|
||||||
@@ -54,3 +55,13 @@ abstract class IrExpressionBase(
|
|||||||
this.index = index
|
this.index = index
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
abstract class IrTerminalExpressionBase(
|
||||||
|
startOffset: Int,
|
||||||
|
endOffset: Int,
|
||||||
|
type: KotlinType
|
||||||
|
) : IrExpressionBase(startOffset, endOffset, type) {
|
||||||
|
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
|
||||||
|
// No children
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -33,16 +33,6 @@ interface IrExpressionOwner1 : IrExpressionOwner {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IrExpressionOwner2 : IrExpressionOwner {
|
|
||||||
var childExpression1: IrExpression?
|
|
||||||
var childExpression2: IrExpression?
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
const val EXPRESSION1_INDEX = 1
|
|
||||||
const val EXPRESSION2_INDEX = 2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IrExpressionOwnerN : IrExpressionOwner {
|
interface IrExpressionOwnerN : IrExpressionOwner {
|
||||||
val childExpressions: List<IrExpression>
|
val childExpressions: List<IrExpression>
|
||||||
fun addChildExpression(child: IrExpression)
|
fun addChildExpression(child: IrExpression)
|
||||||
|
|||||||
@@ -48,14 +48,10 @@ class IrLiteralExpressionImpl<out T> (
|
|||||||
type: KotlinType,
|
type: KotlinType,
|
||||||
override val kind: IrLiteralKind<T>,
|
override val kind: IrLiteralKind<T>,
|
||||||
override val value: T
|
override val value: T
|
||||||
) : IrExpressionBase(startOffset, endOffset, type), IrLiteralExpression<T> {
|
) : IrTerminalExpressionBase(startOffset, endOffset, type), IrLiteralExpression<T> {
|
||||||
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
|
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
|
||||||
visitor.visitLiteral(this, data)
|
visitor.visitLiteral(this, data)
|
||||||
|
|
||||||
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
|
|
||||||
// No children
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun string(startOffset: Int, endOffset: Int, type: KotlinType, value: String): IrLiteralExpressionImpl<String> =
|
fun string(startOffset: Int, endOffset: Int, type: KotlinType, value: String): IrLiteralExpressionImpl<String> =
|
||||||
IrLiteralExpressionImpl(startOffset, endOffset, type, IrLiteralKind.String, value)
|
IrLiteralExpressionImpl(startOffset, endOffset, type, IrLiteralKind.String, value)
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2016 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.ir.expressions
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||||
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
|
||||||
|
interface IrThisExpression : IrExpression {
|
||||||
|
val classDescriptor: ClassDescriptor
|
||||||
|
}
|
||||||
|
|
||||||
|
class IrThisExpressionImpl(
|
||||||
|
startOffset: Int,
|
||||||
|
endOffset: Int,
|
||||||
|
type: KotlinType,
|
||||||
|
override val classDescriptor: ClassDescriptor
|
||||||
|
) : IrTerminalExpressionBase(startOffset, endOffset, type), IrThisExpression {
|
||||||
|
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R {
|
||||||
|
return visitor.visitThisExpression(this, data)
|
||||||
|
}
|
||||||
|
}
|
||||||
+44
@@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2016 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.ir.expressions
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||||
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
|
||||||
|
enum class IrTypeOperator {
|
||||||
|
SMART_AS,
|
||||||
|
AS,
|
||||||
|
AS_SAFE,
|
||||||
|
IS;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IrTypeOperatorExpression : IrExpression, IrCompoundExpression1 {
|
||||||
|
val operator: IrTypeOperator
|
||||||
|
val typeOperand: KotlinType
|
||||||
|
}
|
||||||
|
|
||||||
|
class IrTypeOperatorExpressionImpl(
|
||||||
|
startOffset: Int,
|
||||||
|
endOffset: Int,
|
||||||
|
type: KotlinType,
|
||||||
|
override val operator: IrTypeOperator,
|
||||||
|
override val typeOperand: KotlinType
|
||||||
|
) : IrCompoundExpression1Base(startOffset, endOffset, type), IrTypeOperatorExpression {
|
||||||
|
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R {
|
||||||
|
return visitor.visitTypeOperatorExpression(this, data)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,23 +18,52 @@ package org.jetbrains.kotlin.ir.util
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.ir.IrElement
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrCallExpression
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||||
import org.jetbrains.kotlin.utils.Printer
|
import org.jetbrains.kotlin.utils.Printer
|
||||||
|
|
||||||
fun IrDeclaration.dump(): String {
|
fun IrDeclaration.dump(): String {
|
||||||
val sb = StringBuilder()
|
val sb = StringBuilder()
|
||||||
accept(DumpIrTreeVisitor(sb), null)
|
accept(DumpIrTreeVisitor(sb), "")
|
||||||
return sb.toString()
|
return sb.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
class DumpIrTreeVisitor(out: Appendable): IrElementVisitor<Unit, Nothing?> {
|
class DumpIrTreeVisitor(out: Appendable): IrElementVisitor<Unit, String> {
|
||||||
val printer = Printer(out, " ")
|
val printer = Printer(out, " ")
|
||||||
val elementRenderer = RenderIrElementVisitor()
|
val elementRenderer = RenderIrElementVisitor()
|
||||||
|
|
||||||
override fun visitElement(element: IrElement, data: Nothing?) {
|
override fun visitElement(element: IrElement, data: String) {
|
||||||
printer.println(element.accept(elementRenderer, null))
|
element.dumpLabeledSubTree(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitCallExpression(expression: IrCallExpression, data: String) {
|
||||||
|
expression.dumpLabeledElementWith(data) {
|
||||||
|
expression.dispatchReceiver?.accept(this, "\$this")
|
||||||
|
expression.extensionReceiver?.accept(this, "\$receiver")
|
||||||
|
for (valueParameter in expression.callee.valueParameters) {
|
||||||
|
expression.getValueArgument(valueParameter)?.accept(this, valueParameter.name.asString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private inline fun IrElement.dumpLabeledElementWith(label: String, body: () -> Unit) {
|
||||||
|
printer.println(accept(elementRenderer, null).withLabel(label))
|
||||||
|
indented(body)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IrElement.dumpLabeledSubTree(label: String) {
|
||||||
|
printer.println(accept(elementRenderer, null).withLabel(label))
|
||||||
|
indented {
|
||||||
|
acceptChildren(this@DumpIrTreeVisitor, "")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private inline fun indented(body: () -> Unit) {
|
||||||
printer.pushIndent()
|
printer.pushIndent()
|
||||||
element.acceptChildren(this, null)
|
body()
|
||||||
printer.popIndent()
|
printer.popIndent()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun String.withLabel(label: String) =
|
||||||
|
if (label.isEmpty()) this else "$label: $this"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.ir.util
|
package org.jetbrains.kotlin.ir.util
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
import org.jetbrains.kotlin.ir.IrElement
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.*
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
@@ -27,40 +28,58 @@ import org.jetbrains.kotlin.renderer.OverrideRenderingPolicy
|
|||||||
|
|
||||||
class RenderIrElementVisitor : IrElementVisitor<String, Nothing?> {
|
class RenderIrElementVisitor : IrElementVisitor<String, Nothing?> {
|
||||||
override fun visitElement(element: IrElement, data: Nothing?): String =
|
override fun visitElement(element: IrElement, data: Nothing?): String =
|
||||||
"??? ${element.javaClass.simpleName}"
|
"? ${element.javaClass.simpleName}"
|
||||||
|
|
||||||
override fun visitDeclaration(declaration: IrDeclaration, data: Nothing?): String =
|
override fun visitDeclaration(declaration: IrDeclaration, data: Nothing?): String =
|
||||||
"??? ${declaration.javaClass.simpleName} ${declaration.descriptor?.name}"
|
"? ${declaration.javaClass.simpleName} ${declaration.descriptor?.name}"
|
||||||
|
|
||||||
override fun visitFile(declaration: IrFile, data: Nothing?): String =
|
override fun visitFile(declaration: IrFile, data: Nothing?): String =
|
||||||
"IrFile ${declaration.name}"
|
"IrFile ${declaration.name}"
|
||||||
|
|
||||||
override fun visitFunction(declaration: IrFunction, data: Nothing?): String =
|
override fun visitFunction(declaration: IrFunction, data: Nothing?): String =
|
||||||
"IrFunction ${declaration.renderDescriptor()}"
|
"IrFunction ${declaration.descriptor.render()}"
|
||||||
|
|
||||||
override fun visitProperty(declaration: IrProperty, data: Nothing?): String =
|
override fun visitProperty(declaration: IrProperty, data: Nothing?): String =
|
||||||
"IrProperty ${declaration.renderDescriptor()} getter=${declaration.getter?.name()} setter=${declaration.setter?.name()}"
|
"IrProperty ${declaration.descriptor.render()} getter=${declaration.getter?.name()} setter=${declaration.setter?.name()}"
|
||||||
|
|
||||||
override fun visitPropertyGetter(declaration: IrPropertyGetter, data: Nothing?): String =
|
override fun visitPropertyGetter(declaration: IrPropertyGetter, data: Nothing?): String =
|
||||||
"IrPropertyGetter ${declaration.renderDescriptor()} property=${declaration.property?.name()}"
|
"IrPropertyGetter ${declaration.descriptor.render()} property=${declaration.property?.name()}"
|
||||||
|
|
||||||
override fun visitPropertySetter(declaration: IrPropertySetter, data: Nothing?): String =
|
override fun visitPropertySetter(declaration: IrPropertySetter, data: Nothing?): String =
|
||||||
"IrPropertySetter ${declaration.renderDescriptor()} property=${declaration.property?.name()}"
|
"IrPropertySetter ${declaration.descriptor.render()} property=${declaration.property?.name()}"
|
||||||
|
|
||||||
override fun visitExpressionBody(body: IrExpressionBody, data: Nothing?): String =
|
override fun visitExpressionBody(body: IrExpressionBody, data: Nothing?): String =
|
||||||
"IrExpressionBody"
|
"IrExpressionBody"
|
||||||
|
|
||||||
override fun visitExpression(expression: IrExpression, data: Nothing?): String =
|
override fun visitExpression(expression: IrExpression, data: Nothing?): String =
|
||||||
"??? ${expression.javaClass.simpleName} type=${expression.renderType()}"
|
"? ${expression.javaClass.simpleName} type=${expression.renderType()}"
|
||||||
|
|
||||||
override fun <T> visitLiteral(expression: IrLiteralExpression<T>, data: Nothing?): String =
|
override fun <T> visitLiteral(expression: IrLiteralExpression<T>, data: Nothing?): String =
|
||||||
"IrLiteral ${expression.kind} type=${expression.renderType()} value='${expression.value}'"
|
"LITERAL ${expression.kind} type=${expression.renderType()} value='${expression.value}'"
|
||||||
|
|
||||||
override fun visitBlockExpression(expression: IrBlockExpression, data: Nothing?): String =
|
override fun visitBlockExpression(expression: IrBlockExpression, data: Nothing?): String =
|
||||||
"IrBlockExpression type=${expression.renderType()}"
|
"BLOCK type=${expression.renderType()}"
|
||||||
|
|
||||||
override fun visitReturnExpression(expression: IrReturnExpression, data: Nothing?): String =
|
override fun visitReturnExpression(expression: IrReturnExpression, data: Nothing?): String =
|
||||||
"IrReturnExpression type=${expression.renderType()}"
|
"RETURN type=${expression.renderType()}"
|
||||||
|
|
||||||
|
override fun visitVariableReference(expression: IrVariableReference, data: Nothing?): String =
|
||||||
|
"VAR ${expression.descriptor.name}"
|
||||||
|
|
||||||
|
override fun visitSingletonReference(expression: IrSingletonReference, data: Nothing?): String =
|
||||||
|
"SINGLETON ${expression.descriptor.name}"
|
||||||
|
|
||||||
|
override fun visitExtensionReceiverReference(expression: IrExtensionReceiverReference, data: Nothing?): String =
|
||||||
|
"\$RECEIVER of: ${expression.descriptor.containingDeclaration.name}"
|
||||||
|
|
||||||
|
override fun visitThisExpression(expression: IrThisExpression, data: Nothing?): String =
|
||||||
|
"THIS ${expression.classDescriptor.render()}"
|
||||||
|
|
||||||
|
override fun visitCallExpression(expression: IrCallExpression, data: Nothing?): String =
|
||||||
|
"CALL ${expression.callee.name} ${expression.operator ?: ""}"
|
||||||
|
|
||||||
|
override fun visitDummyExpression(expression: IrDummyExpression, data: Nothing?): String =
|
||||||
|
"DUMMY ${expression.description}"
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val DESCRIPTOR_RENDERER = DescriptorRenderer.withOptions {
|
private val DESCRIPTOR_RENDERER = DescriptorRenderer.withOptions {
|
||||||
@@ -72,8 +91,13 @@ class RenderIrElementVisitor : IrElementVisitor<String, Nothing?> {
|
|||||||
modifiers = DescriptorRendererModifier.ALL
|
modifiers = DescriptorRendererModifier.ALL
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun IrDeclaration.name(): String = descriptor?.let { it.name.toString() } ?: "<none>"
|
internal fun IrDeclaration.name(): String =
|
||||||
private fun IrDeclaration.renderDescriptor(): String = descriptor?.let { DESCRIPTOR_RENDERER.render(it) } ?: "<none>"
|
descriptor?.let { it.name.toString() } ?: "<none>"
|
||||||
private fun IrExpression.renderType(): String = DESCRIPTOR_RENDERER.renderType(type)
|
|
||||||
|
internal fun DeclarationDescriptor.render(): String =
|
||||||
|
DESCRIPTOR_RENDERER.render(this)
|
||||||
|
|
||||||
|
internal fun IrExpression.renderType(): String =
|
||||||
|
DESCRIPTOR_RENDERER.renderType(type)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -43,4 +43,18 @@ interface IrElementVisitor<out R, in D> {
|
|||||||
fun visitReturnExpression(expression: IrReturnExpression, data: D): R = visitExpression(expression, data)
|
fun visitReturnExpression(expression: IrReturnExpression, data: D): R = visitExpression(expression, data)
|
||||||
fun visitBlockExpression(expression: IrBlockExpression, data: D): R = visitExpression(expression, data)
|
fun visitBlockExpression(expression: IrBlockExpression, data: D): R = visitExpression(expression, data)
|
||||||
fun visitStringTemplate(expression: IrStringConcatenationExpression, data: D) = visitExpression(expression, data)
|
fun visitStringTemplate(expression: IrStringConcatenationExpression, data: D) = visitExpression(expression, data)
|
||||||
|
fun visitThisExpression(expression: IrThisExpression, data: D) = visitExpression(expression, data)
|
||||||
|
fun visitDeclarationReference(expression: IrDeclarationReference, data: D) = visitExpression(expression, data)
|
||||||
|
fun visitVariableReference(expression: IrVariableReference, data: D) = visitDeclarationReference(expression, data)
|
||||||
|
fun visitSingletonReference(expression: IrSingletonReference, data: D) = visitDeclarationReference(expression, data)
|
||||||
|
fun visitExtensionReceiverReference(expression: IrExtensionReceiverReference, data: D) = visitDeclarationReference(expression, data)
|
||||||
|
|
||||||
|
|
||||||
|
fun visitCallExpression(expression: IrCallExpression, data: D) = visitExpression(expression, data)
|
||||||
|
fun visitTypeOperatorExpression(expression: IrTypeOperatorExpression, data: D) = visitExpression(expression, data)
|
||||||
|
|
||||||
|
// NB Use it only for testing purposes; will be removed as soon as all Kotlin expression types are covered
|
||||||
|
fun visitDummyExpression(expression: IrDummyExpression, data: D) = visitExpression(expression, data)
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -1,5 +1,5 @@
|
|||||||
IrFile /boxOk.kt
|
IrFile /boxOk.kt
|
||||||
IrFunction public fun box(): kotlin.String
|
IrFunction public fun box(): kotlin.String
|
||||||
IrExpressionBody
|
IrExpressionBody
|
||||||
IrReturnExpression type=kotlin.String
|
RETURN type=kotlin.String
|
||||||
IrLiteral String type=kotlin.String value='OK'
|
LITERAL String type=kotlin.String value='OK'
|
||||||
|
|||||||
Vendored
+8
@@ -0,0 +1,8 @@
|
|||||||
|
fun foo(x: Int, y: Int) = x
|
||||||
|
fun bar(x: Int) = foo(x, 1)
|
||||||
|
fun qux(x: Int) = foo(foo(x, x), x)
|
||||||
|
|
||||||
|
fun Int.ext1() = this
|
||||||
|
fun Int.ext2(x: Int) = foo(this, x)
|
||||||
|
|
||||||
|
// IR_FILE_TXT calls.txt
|
||||||
+29
@@ -0,0 +1,29 @@
|
|||||||
|
IrFile /calls.kt
|
||||||
|
IrFunction public fun foo(/*0*/ x: kotlin.Int, /*1*/ y: kotlin.Int): kotlin.Int
|
||||||
|
IrExpressionBody
|
||||||
|
RETURN type=kotlin.Int
|
||||||
|
VAR x
|
||||||
|
IrFunction public fun bar(/*0*/ x: kotlin.Int): kotlin.Int
|
||||||
|
IrExpressionBody
|
||||||
|
RETURN type=kotlin.Int
|
||||||
|
CALL foo
|
||||||
|
x: VAR x
|
||||||
|
y: LITERAL Int type=kotlin.Int value='1'
|
||||||
|
IrFunction public fun qux(/*0*/ x: kotlin.Int): kotlin.Int
|
||||||
|
IrExpressionBody
|
||||||
|
RETURN type=kotlin.Int
|
||||||
|
CALL foo
|
||||||
|
x: CALL foo
|
||||||
|
x: VAR x
|
||||||
|
y: VAR x
|
||||||
|
y: VAR x
|
||||||
|
IrFunction public fun kotlin.Int.ext1(): kotlin.Int
|
||||||
|
IrExpressionBody
|
||||||
|
RETURN type=kotlin.Int
|
||||||
|
DUMMY KtThisExpression
|
||||||
|
IrFunction public fun kotlin.Int.ext2(/*0*/ x: kotlin.Int): kotlin.Int
|
||||||
|
IrExpressionBody
|
||||||
|
RETURN type=kotlin.Int
|
||||||
|
CALL foo
|
||||||
|
x: DUMMY KtThisExpression
|
||||||
|
y: VAR x
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
val String.okext: String get() = "OK"
|
||||||
|
fun String.test5() = okext
|
||||||
|
|
||||||
|
// IR_FILE_TXT extensionPropertyGetterCall.txt
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
IrFile /extensionPropertyGetterCall.kt
|
||||||
|
IrProperty public val kotlin.String.okext: kotlin.String getter=<get-okext> setter=null
|
||||||
|
IrPropertyGetter public fun kotlin.String.<get-okext>(): kotlin.String property=okext
|
||||||
|
IrExpressionBody
|
||||||
|
RETURN type=kotlin.String
|
||||||
|
LITERAL String type=kotlin.String value='OK'
|
||||||
|
IrFunction public fun kotlin.String.test5(): kotlin.String
|
||||||
|
IrExpressionBody
|
||||||
|
RETURN type=kotlin.String
|
||||||
|
CALL okext PROPERTY_GET
|
||||||
|
$receiver: $RECEIVER of: test5
|
||||||
+19
@@ -0,0 +1,19 @@
|
|||||||
|
val ok = "OK"
|
||||||
|
val ok2 = ok
|
||||||
|
val ok3: String get() = "OK"
|
||||||
|
|
||||||
|
fun test1() = ok
|
||||||
|
|
||||||
|
fun test2(x: String) = x
|
||||||
|
|
||||||
|
fun test3(): String {
|
||||||
|
val x = "OK"
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test4() = ok3
|
||||||
|
|
||||||
|
val String.okext: String get() = "OK"
|
||||||
|
fun String.test5() = okext
|
||||||
|
|
||||||
|
// IR_FILE_TXT references.txt
|
||||||
+42
@@ -0,0 +1,42 @@
|
|||||||
|
IrFile /references.kt
|
||||||
|
IrProperty public val ok: kotlin.String = "OK" getter=null setter=null
|
||||||
|
IrExpressionBody
|
||||||
|
RETURN type=kotlin.String
|
||||||
|
LITERAL String type=kotlin.String value='OK'
|
||||||
|
IrProperty public val ok2: kotlin.String = "OK" getter=null setter=null
|
||||||
|
IrExpressionBody
|
||||||
|
RETURN type=kotlin.String
|
||||||
|
CALL ok PROPERTY_GET
|
||||||
|
IrProperty public val ok3: kotlin.String getter=<get-ok3> setter=null
|
||||||
|
IrPropertyGetter public fun <get-ok3>(): kotlin.String property=ok3
|
||||||
|
IrExpressionBody
|
||||||
|
RETURN type=kotlin.String
|
||||||
|
LITERAL String type=kotlin.String value='OK'
|
||||||
|
IrFunction public fun test1(): kotlin.String
|
||||||
|
IrExpressionBody
|
||||||
|
RETURN type=kotlin.String
|
||||||
|
CALL ok PROPERTY_GET
|
||||||
|
IrFunction public fun test2(/*0*/ x: kotlin.String): kotlin.String
|
||||||
|
IrExpressionBody
|
||||||
|
RETURN type=kotlin.String
|
||||||
|
VAR x
|
||||||
|
IrFunction public fun test3(): kotlin.String
|
||||||
|
IrExpressionBody
|
||||||
|
BLOCK type=kotlin.Nothing
|
||||||
|
DUMMY KtProperty
|
||||||
|
RETURN type=kotlin.Nothing
|
||||||
|
VAR x
|
||||||
|
IrFunction public fun test4(): kotlin.String
|
||||||
|
IrExpressionBody
|
||||||
|
RETURN type=kotlin.String
|
||||||
|
CALL ok3 PROPERTY_GET
|
||||||
|
IrProperty public val kotlin.String.okext: kotlin.String getter=<get-okext> setter=null
|
||||||
|
IrPropertyGetter public fun kotlin.String.<get-okext>(): kotlin.String property=okext
|
||||||
|
IrExpressionBody
|
||||||
|
RETURN type=kotlin.String
|
||||||
|
LITERAL String type=kotlin.String value='OK'
|
||||||
|
IrFunction public fun kotlin.String.test5(): kotlin.String
|
||||||
|
IrExpressionBody
|
||||||
|
RETURN type=kotlin.String
|
||||||
|
CALL okext PROPERTY_GET
|
||||||
|
$receiver: $RECEIVER of: test5
|
||||||
+12
-12
@@ -1,27 +1,27 @@
|
|||||||
IrFile /smoke.kt
|
IrFile /smoke.kt
|
||||||
IrFunction public fun testFun(): kotlin.String
|
IrFunction public fun testFun(): kotlin.String
|
||||||
IrExpressionBody
|
IrExpressionBody
|
||||||
IrBlockExpression type=kotlin.Nothing
|
BLOCK type=kotlin.Nothing
|
||||||
IrReturnExpression type=kotlin.Nothing
|
RETURN type=kotlin.Nothing
|
||||||
IrLiteral String type=kotlin.String value='OK'
|
LITERAL String type=kotlin.String value='OK'
|
||||||
IrProperty public val testSimpleVal: kotlin.Int = 1 getter=null setter=null
|
IrProperty public val testSimpleVal: kotlin.Int = 1 getter=null setter=null
|
||||||
IrExpressionBody
|
IrExpressionBody
|
||||||
IrReturnExpression type=kotlin.Int
|
RETURN type=kotlin.Int
|
||||||
IrLiteral Int type=kotlin.Int value='1'
|
LITERAL Int type=kotlin.Int value='1'
|
||||||
IrProperty public val testValWithGetter: kotlin.Int getter=<get-testValWithGetter> setter=null
|
IrProperty public val testValWithGetter: kotlin.Int getter=<get-testValWithGetter> setter=null
|
||||||
IrPropertyGetter public fun <get-testValWithGetter>(): kotlin.Int property=testValWithGetter
|
IrPropertyGetter public fun <get-testValWithGetter>(): kotlin.Int property=testValWithGetter
|
||||||
IrExpressionBody
|
IrExpressionBody
|
||||||
IrReturnExpression type=kotlin.Int
|
RETURN type=kotlin.Int
|
||||||
IrLiteral Int type=kotlin.Int value='42'
|
LITERAL Int type=kotlin.Int value='42'
|
||||||
IrProperty public var testSimpleVar: kotlin.Int getter=null setter=null
|
IrProperty public var testSimpleVar: kotlin.Int getter=null setter=null
|
||||||
IrExpressionBody
|
IrExpressionBody
|
||||||
IrReturnExpression type=kotlin.Int
|
RETURN type=kotlin.Int
|
||||||
IrLiteral Int type=kotlin.Int value='2'
|
LITERAL Int type=kotlin.Int value='2'
|
||||||
IrProperty public var testVarWithAccessors: kotlin.Int getter=<get-testVarWithAccessors> setter=<set-testVarWithAccessors>
|
IrProperty public var testVarWithAccessors: kotlin.Int getter=<get-testVarWithAccessors> setter=<set-testVarWithAccessors>
|
||||||
IrPropertyGetter public fun <get-testVarWithAccessors>(): kotlin.Int property=testVarWithAccessors
|
IrPropertyGetter public fun <get-testVarWithAccessors>(): kotlin.Int property=testVarWithAccessors
|
||||||
IrExpressionBody
|
IrExpressionBody
|
||||||
IrReturnExpression type=kotlin.Int
|
RETURN type=kotlin.Int
|
||||||
IrLiteral Int type=kotlin.Int value='42'
|
LITERAL Int type=kotlin.Int value='42'
|
||||||
IrPropertySetter public fun <set-testVarWithAccessors>(/*0*/ v: kotlin.Int): kotlin.Unit property=testVarWithAccessors
|
IrPropertySetter public fun <set-testVarWithAccessors>(/*0*/ v: kotlin.Int): kotlin.Unit property=testVarWithAccessors
|
||||||
IrExpressionBody
|
IrExpressionBody
|
||||||
IrBlockExpression type=kotlin.Unit
|
BLOCK type=kotlin.Unit
|
||||||
|
|||||||
@@ -41,6 +41,24 @@ public class IrTextTestCaseGenerated extends AbstractIrTextTestCase {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("calls.kt")
|
||||||
|
public void testCalls() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/calls.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("extensionPropertyGetterCall.kt")
|
||||||
|
public void testExtensionPropertyGetterCall() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/extensionPropertyGetterCall.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("references.kt")
|
||||||
|
public void testReferences() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/references.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("smoke.kt")
|
@TestMetadata("smoke.kt")
|
||||||
public void testSmoke() throws Exception {
|
public void testSmoke() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/smoke.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/smoke.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user