Generate class members (functions, properties, nested classes).

This commit is contained in:
Dmitry Petrov
2016-08-25 18:33:12 +03:00
committed by Dmitry Petrov
parent 19e95d232a
commit 703d3405ed
13 changed files with 174 additions and 56 deletions
@@ -16,10 +16,9 @@
package org.jetbrains.kotlin.psi2ir.generators
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrClassImpl
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtParameter
import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.startOffset
import org.jetbrains.kotlin.resolve.BindingContext
@@ -30,7 +29,38 @@ class ClassGenerator(val declarationGenerator: DeclarationGenerator) : Generator
fun generateClass(ktClassOrObject: KtClassOrObject): IrClass {
val descriptor = getOrFail(BindingContext.CLASS, ktClassOrObject)
val irClass = IrClassImpl(ktClassOrObject.startOffset, ktClassOrObject.endOffset, IrDeclarationOrigin.DEFINED, descriptor)
// TODO generate members
generatePropertiesDeclaredInPrimaryConstructor(irClass, ktClassOrObject)
generateMembersDeclaredInClassbody(irClass, ktClassOrObject)
return irClass
}
private fun generatePropertiesDeclaredInPrimaryConstructor(irClass: IrClassImpl, ktClassOrObject: KtClassOrObject) {
ktClassOrObject.getPrimaryConstructor()?.let { ktPrimaryConstructor ->
for (ktParameter in ktPrimaryConstructor.valueParameters) {
if (ktParameter.hasValOrVar()) {
irClass.addMember(generatePropertyForPrimaryConstructorParameter(ktParameter))
}
}
}
}
private fun generateMembersDeclaredInClassbody(irClass: IrClassImpl, ktClassOrObject: KtClassOrObject) {
ktClassOrObject.getBody()?.let { ktClassBody ->
for (ktDeclaration in ktClassBody.declarations) {
val irMember = declarationGenerator.generateMemberDeclaration(ktDeclaration)
irClass.addMember(irMember)
if (irMember is IrProperty) {
irMember.getter?.let { irClass.addMember(it) }
irMember.setter?.let { irClass.addMember(it) }
}
}
}
}
private fun generatePropertyForPrimaryConstructorParameter(ktParameter: KtParameter): IrDeclaration {
val propertyDescriptor = getOrFail(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, ktParameter)
return IrSimplePropertyImpl(ktParameter.startOffset, ktParameter.endOffset, IrDeclarationOrigin.DEFINED, propertyDescriptor)
}
}
@@ -49,62 +49,41 @@ class DeclarationGenerator(override val context: GeneratorContext) : Generator {
IrTypeAliasImpl(ktDeclaration.startOffset, ktDeclaration.endOffset, IrDeclarationOrigin.DEFINED,
getOrFail(BindingContext.TYPE_ALIAS, ktDeclaration))
fun generateFunctionDeclaration(ktNamedFunction: KtNamedFunction): IrFunction {
val functionDescriptor = getOrFail(BindingContext.FUNCTION, ktNamedFunction)
val body = generateFunctionBody(functionDescriptor, ktNamedFunction.bodyExpression ?: TODO("function without body expression"))
return createFunction(ktNamedFunction, functionDescriptor, body)
fun generateFunctionDeclaration(ktFunction: KtNamedFunction): IrFunction {
val functionDescriptor = getOrFail(BindingContext.FUNCTION, ktFunction)
val body = ktFunction.bodyExpression?.let { generateFunctionBody(functionDescriptor, it) }
return IrFunctionImpl(ktFunction.startOffset, ktFunction.endOffset, IrDeclarationOrigin.DEFINED,
functionDescriptor, body)
}
fun generatePropertyDeclaration(ktProperty: KtProperty): IrProperty {
val propertyDescriptor = getPropertyDescriptor(ktProperty)
if (ktProperty.hasDelegate()) TODO("handle delegated property")
val initializer = ktProperty.initializer?.let { generateInitializerBody(propertyDescriptor, it) }
val irProperty = createSimpleProperty(ktProperty, propertyDescriptor, initializer)
val irProperty = IrSimplePropertyImpl(ktProperty.startOffset, ktProperty.endOffset, IrDeclarationOrigin.DEFINED,
propertyDescriptor, initializer)
ktProperty.getter?.let { ktGetter ->
val accessorDescriptor = getOrFail(BindingContext.PROPERTY_ACCESSOR, ktGetter)
val getterDescriptor = accessorDescriptor as? PropertyGetterDescriptor ?: TODO("not a getter?")
val getterBody = generateFunctionBody(getterDescriptor, ktGetter.bodyExpression ?: TODO("default getter"))
createPropertyGetter(ktGetter, irProperty, getterDescriptor, getterBody)
val irGetterBody = generateFunctionBody(getterDescriptor, ktGetter.bodyExpression ?: TODO("default getter"))
val irGetter = IrPropertyGetterImpl(ktGetter.startOffset, ktGetter.endOffset, IrDeclarationOrigin.DEFINED,
getterDescriptor, irGetterBody)
irProperty.getter = irGetter
}
ktProperty.setter?.let { ktSetter ->
val accessorDescriptor = getOrFail(BindingContext.PROPERTY_ACCESSOR, ktSetter)
val setterDescriptor = accessorDescriptor as? PropertySetterDescriptor ?: TODO("not a setter?")
val setterBody = generateFunctionBody(setterDescriptor, ktSetter.bodyExpression ?: TODO("default setter"))
createPropertySetter(ktSetter, irProperty, setterDescriptor, setterBody)
val irSetterBody = generateFunctionBody(setterDescriptor, ktSetter.bodyExpression ?: TODO("default setter"))
val irSetter = IrPropertySetterImpl(ktSetter.startOffset, ktSetter.endOffset, IrDeclarationOrigin.DEFINED,
setterDescriptor, irSetterBody)
irProperty.setter = irSetter
}
return irProperty
}
fun createFunction(ktFunction: KtFunction, functionDescriptor: FunctionDescriptor, body: IrBody): IrFunction =
IrFunctionImpl(ktFunction.startOffset, ktFunction.endOffset,
IrDeclarationOrigin.DEFINED, functionDescriptor, body)
fun createSimpleProperty(ktProperty: KtProperty, propertyDescriptor: PropertyDescriptor, valueInitializer: IrBody?): IrSimpleProperty =
IrSimplePropertyImpl(ktProperty.startOffset, ktProperty.endOffset,
IrDeclarationOrigin.DEFINED, propertyDescriptor, valueInitializer)
fun createPropertyGetter(
ktPropertyAccessor: KtPropertyAccessor,
irProperty: IrProperty,
getterDescriptor: PropertyGetterDescriptor,
getterBody: IrBody
): IrPropertyGetter =
IrPropertyGetterImpl(ktPropertyAccessor.startOffset, ktPropertyAccessor.endOffset,
IrDeclarationOrigin.DEFINED, getterDescriptor, getterBody)
.apply { irProperty.getter = this }
fun createPropertySetter(
ktPropertyAccessor: KtPropertyAccessor,
irProperty: IrProperty,
setterDescriptor: PropertySetterDescriptor,
setterBody: IrBody
) : IrPropertySetter =
IrPropertySetterImpl(ktPropertyAccessor.startOffset, ktPropertyAccessor.endOffset,
IrDeclarationOrigin.DEFINED, setterDescriptor, setterBody)
.apply { irProperty.setter = this }
private fun getPropertyDescriptor(ktProperty: KtProperty): PropertyDescriptor {
val variableDescriptor = getOrFail(BindingContext.VARIABLE, ktProperty)
@@ -0,0 +1,50 @@
/*
* 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.declarations
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
import org.jetbrains.kotlin.ir.expressions.IrBody
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
interface IrConstructor : IrFunction {
override val declarationKind: IrDeclarationKind
get() = IrDeclarationKind.CONSTRUCTOR
override val descriptor: ConstructorDescriptor
}
class IrConstructorImpl(
startOffset: Int,
endOffset: Int,
origin: IrDeclarationOrigin,
override val descriptor: ConstructorDescriptor
) : IrFunctionBase(startOffset, endOffset, origin), IrConstructor {
constructor(
startOffset: Int,
endOffset: Int,
origin: IrDeclarationOrigin,
descriptor: ConstructorDescriptor,
body: IrBody
) : this(startOffset, endOffset, origin, descriptor) {
this.body = body
}
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R {
return visitor.visitConstructor(this, data)
}
}
@@ -23,7 +23,7 @@ import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
interface IrFunction : IrDeclaration {
override val descriptor: FunctionDescriptor
val body: IrBody
val body: IrBody?
override val declarationKind: IrDeclarationKind
get() = IrDeclarationKind.FUNCTION
@@ -32,21 +32,23 @@ interface IrFunction : IrDeclaration {
abstract class IrFunctionBase(
startOffset: Int,
endOffset: Int,
origin: IrDeclarationOrigin,
body: IrBody? = null
origin: IrDeclarationOrigin
) : IrDeclarationBase(startOffset, endOffset, origin), IrFunction {
init {
body?.setTreeLocation(this, FUNCTION_BODY_SLOT)
constructor(
startOffset: Int,
endOffset: Int,
origin: IrDeclarationOrigin,
body: IrBody
) : this(startOffset, endOffset, origin) {
this.body = body
}
private var bodyImpl: IrBody? = body
override var body: IrBody
get() = bodyImpl!!
final override var body: IrBody? = null
set(newValue) {
newValue.assertDetached()
bodyImpl?.detach()
bodyImpl = newValue
newValue.setTreeLocation(this, FUNCTION_BODY_SLOT)
newValue?.assertDetached()
field?.detach()
field = newValue
newValue?.setTreeLocation(this, FUNCTION_BODY_SLOT)
}
override fun getChild(slot: Int): IrElement? =
@@ -63,7 +65,7 @@ abstract class IrFunctionBase(
}
override fun <D> acceptChildren(visitor: IrElementVisitor<Unit, D>, data: D) {
body.accept(visitor, data)
body?.accept(visitor, data)
}
}
@@ -71,9 +73,18 @@ class IrFunctionImpl(
startOffset: Int,
endOffset: Int,
origin: IrDeclarationOrigin,
override val descriptor: FunctionDescriptor,
body: IrBody
) : IrFunctionBase(startOffset, endOffset, origin, body) {
override val descriptor: FunctionDescriptor
) : IrFunctionBase(startOffset, endOffset, origin) {
constructor(
startOffset: Int,
endOffset: Int,
origin: IrDeclarationOrigin,
descriptor: FunctionDescriptor,
body: IrBody?
) : this(startOffset, endOffset, origin, descriptor) {
this.body = body
}
override fun <R, D> accept(visitor: IrElementVisitor<R, D>, data: D): R =
visitor.visitFunction(this, data)
}
@@ -31,6 +31,7 @@ interface IrElementVisitor<out R, in D> {
fun visitFunction(declaration: IrFunction, data: D): R = visitDeclaration(declaration, data)
fun visitPropertyGetter(declaration: IrPropertyGetter, data: D): R = visitFunction(declaration, data)
fun visitPropertySetter(declaration: IrPropertySetter, data: D): R = visitFunction(declaration, data)
fun visitConstructor(declaration: IrConstructor, data: D): R = visitFunction(declaration, data)
fun visitProperty(declaration: IrProperty, data: D): R = visitDeclaration(declaration, data)
fun visitSimpleProperty(declaration: IrSimpleProperty, data: D): R = visitProperty(declaration, data)
fun visitDelegatedProperty(declaration: IrDelegatedProperty, data: D): R = visitProperty(declaration, data)
@@ -12,6 +12,7 @@ FILE /arrayAugmentedAssignment1.kt
RETURN type=kotlin.Nothing
CONST Int type=kotlin.Int value='42'
CLASS CLASS C
PROPERTY public final val x: kotlin.IntArray getter=null setter=null
FUN public fun testVariable(): kotlin.Unit
BLOCK_BODY
VAR var x: kotlin.IntArray
@@ -1,6 +1,8 @@
FILE /arrayAugmentedAssignment2.kt
CLASS INTERFACE IA
FUN public abstract operator fun get(/*0*/ index: kotlin.String): kotlin.Int
CLASS INTERFACE IB
FUN public abstract operator fun IA.set(/*0*/ index: kotlin.String, /*1*/ value: kotlin.Int): kotlin.Unit
FUN public fun IB.test(/*0*/ a: IA): kotlin.Unit
BLOCK_BODY
BLOCK type=kotlin.Unit operator=PLUSEQ
+1
View File
@@ -1,5 +1,6 @@
FILE /assignments.kt
CLASS CLASS Ref
PROPERTY public final var x: kotlin.Int getter=null setter=null
FUN public fun test1(): kotlin.Unit
BLOCK_BODY
VAR var x: kotlin.Int
+8
View File
@@ -1,5 +1,13 @@
FILE /chainOfSafeCalls.kt
CLASS CLASS C
FUN public final fun foo(): C
BLOCK_BODY
RETURN type=kotlin.Nothing
THIS public final class C type=C
FUN public final fun bar(): C?
BLOCK_BODY
RETURN type=kotlin.Nothing
THIS public final class C type=C
FUN public fun test(/*0*/ nc: C?): C?
BLOCK_BODY
RETURN type=kotlin.Nothing
+1
View File
@@ -1,6 +1,7 @@
FILE /conventionComparisons.kt
CLASS INTERFACE IA
CLASS INTERFACE IB
FUN public abstract operator fun IA.compareTo(/*0*/ other: IA): kotlin.Int
FUN public fun IB.test1(/*0*/ a1: IA, /*1*/ a2: IA): kotlin.Boolean
BLOCK_BODY
RETURN type=kotlin.Nothing
@@ -1,7 +1,33 @@
FILE /forWithImplicitReceivers.kt
CLASS OBJECT FiveTimes
CLASS CLASS IntCell
PROPERTY public final var value: kotlin.Int getter=null setter=null
CLASS INTERFACE IReceiver
FUN public open operator fun FiveTimes.iterator(): IntCell
BLOCK_BODY
RETURN type=kotlin.Nothing
CALL .<init> type=IntCell operator=null
value: CONST Int type=kotlin.Int value='5'
FUN public open operator fun IntCell.hasNext(): kotlin.Boolean
BLOCK_BODY
RETURN type=kotlin.Nothing
CALL .GT0 type=kotlin.Boolean operator=GT
arg0: CALL .compareTo type=kotlin.Int operator=GT
$this: CALL .<get-value> type=kotlin.Int operator=GET_PROPERTY
$this: $RECEIVER of: hasNext type=IntCell
other: CONST Int type=kotlin.Int value='0'
FUN public open operator fun IntCell.next(): kotlin.Int
BLOCK_BODY
RETURN type=kotlin.Nothing
BLOCK type=kotlin.Int operator=POSTFIX_DECR
VAR val tmp0: kotlin.Int
CALL .<get-value> type=kotlin.Int operator=POSTFIX_DECR
$this: $RECEIVER of: next type=IntCell
CALL .<set-value> type=kotlin.Unit operator=POSTFIX_DECR
$this: $RECEIVER of: next type=IntCell
<set-?>: CALL .dec type=kotlin.Int operator=POSTFIX_DECR
$this: GET_VAR tmp0 type=kotlin.Int operator=null
GET_VAR tmp0 type=kotlin.Int operator=null
FUN public fun IReceiver.test(): kotlin.Unit
BLOCK_BODY
BLOCK type=kotlin.Unit operator=FOR_LOOP
+6
View File
@@ -1,6 +1,12 @@
FILE /safeCalls.kt
CLASS CLASS Ref
PROPERTY public final var value: kotlin.Int getter=null setter=null
CLASS INTERFACE IHost
FUN public open fun kotlin.String.extLength(): kotlin.Int
BLOCK_BODY
RETURN type=kotlin.Nothing
CALL .<get-length> type=kotlin.Int operator=GET_PROPERTY
$this: $RECEIVER of: extLength type=kotlin.String
FUN public fun test1(/*0*/ x: kotlin.String?): kotlin.Int?
BLOCK_BODY
RETURN type=kotlin.Nothing
+2
View File
@@ -1,10 +1,12 @@
FILE /values.kt
CLASS ENUM_CLASS Enum
CLASS ENUM_ENTRY A
CLASS OBJECT A
PROPERTY public val a: kotlin.Int = 0 getter=null setter=null
EXPRESSION_BODY
CONST Int type=kotlin.Int value='0'
CLASS CLASS Z
CLASS OBJECT Companion
FUN public fun test1(): Enum
BLOCK_BODY
RETURN type=kotlin.Nothing