Generate synthetic getter & setter descriptors for static properties in Java classes
(recognized as properties defined in classes without dispatchReceiver and extensionReceiver). Fix 'when' generation for else-only case.
This commit is contained in:
committed by
Dmitry Petrov
parent
05b9eda809
commit
b3f605c4c4
+2
-1
@@ -154,7 +154,8 @@ class AssignmentGenerator(statementGenerator: StatementGenerator) : StatementGen
|
||||
|
||||
val superQualifier = getSuperQualifier(resolvedCall)
|
||||
|
||||
return SimplePropertyLValue(scope, ktLeft.startOffset, ktLeft.endOffset, irOperator, descriptor, propertyReceiver, superQualifier)
|
||||
return SimplePropertyLValue(context, scope, ktLeft.startOffset, ktLeft.endOffset, irOperator, descriptor,
|
||||
propertyReceiver, superQualifier)
|
||||
}
|
||||
|
||||
private fun isValInitializationInConstructor(descriptor: PropertyDescriptor, resolvedCall: ResolvedCall<*>): Boolean =
|
||||
|
||||
+1
-1
@@ -101,7 +101,7 @@ class BranchingExpressionGenerator(statementGenerator: StatementGenerator) : Sta
|
||||
|
||||
private fun generateWhenBody(expression: KtWhenExpression, irSubject: IrVariable?, irWhen: IrWhen): IrExpression {
|
||||
if (irSubject == null) {
|
||||
if (irWhen.branchesCount == 0)
|
||||
if (irWhen.branchesCount == 0 && irWhen.elseBranch == null)
|
||||
return IrBlockImpl(expression.startOffset, expression.endOffset, context.builtIns.unitType, IrOperator.WHEN)
|
||||
else
|
||||
return irWhen
|
||||
|
||||
@@ -60,7 +60,7 @@ class CallGenerator(statementGenerator: StatementGenerator): StatementGeneratorE
|
||||
): IrExpression {
|
||||
return call.callReceiver.call { dispatchReceiverValue, extensionReceiverValue ->
|
||||
val getter = descriptor.getter ?:
|
||||
throw AssertionError("No getter for property $descriptor")
|
||||
context.syntheticDescriptorsFactory.getOrCreatePropertyGetter(descriptor)
|
||||
IrGetterCallImpl(startOffset, endOffset, getter,
|
||||
dispatchReceiverValue?.load(),
|
||||
extensionReceiverValue?.load(),
|
||||
|
||||
+3
-2
@@ -18,17 +18,18 @@ package org.jetbrains.kotlin.psi2ir.generators
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.ir.declarations.IrModuleImpl
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi2ir.PsiSourceManager
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.storage.LockBasedStorageManager
|
||||
|
||||
class GeneratorContext(
|
||||
val moduleDescriptor: ModuleDescriptor,
|
||||
val bindingContext: BindingContext
|
||||
) {
|
||||
val storageManager = LockBasedStorageManager.NO_LOCKS
|
||||
val sourceManager = PsiSourceManager()
|
||||
val syntheticDescriptorsFactory by lazy { SyntheticDescriptorsFactory(storageManager) }
|
||||
|
||||
val builtIns: KotlinBuiltIns get() = moduleDescriptor.builtIns
|
||||
val irBuiltIns = IrBuiltIns(builtIns)
|
||||
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* 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.psi2ir.generators
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyGetterDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertySetterDescriptor
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrSyntheticStaticPropertyGetterDescriptorImpl
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrSyntheticStaticPropertySetterDescriptorImpl
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
|
||||
|
||||
class SyntheticDescriptorsFactory(storageManager: StorageManager) {
|
||||
private val propertyGetters = storageManager.createMemoizedFunction<PropertyDescriptor, PropertyGetterDescriptor> {
|
||||
property ->
|
||||
when {
|
||||
isStaticPropertyInClass(property) ->
|
||||
IrSyntheticStaticPropertyGetterDescriptorImpl(property)
|
||||
else ->
|
||||
throw AssertionError("Don't know how to create synthetic getter for $property")
|
||||
}
|
||||
}
|
||||
|
||||
private val propertySetters = storageManager.createMemoizedFunction<PropertyDescriptor, PropertySetterDescriptor> {
|
||||
property ->
|
||||
when {
|
||||
isStaticPropertyInClass(property) ->
|
||||
IrSyntheticStaticPropertySetterDescriptorImpl(property)
|
||||
else ->
|
||||
throw AssertionError("Don't know how to create synthetic setter for $property")
|
||||
}
|
||||
}
|
||||
|
||||
private fun isStaticPropertyInClass(propertyDescriptor: PropertyDescriptor): Boolean =
|
||||
propertyDescriptor.containingDeclaration is ClassDescriptor &&
|
||||
propertyDescriptor.dispatchReceiverParameter == null &&
|
||||
propertyDescriptor.extensionReceiverParameter == null
|
||||
|
||||
fun getOrCreatePropertyGetter(propertyDescriptor: PropertyDescriptor): PropertyGetterDescriptor =
|
||||
propertyGetters(propertyDescriptor)
|
||||
|
||||
fun getOrCreatePropertySetter(propertyDescriptor: PropertyDescriptor): PropertySetterDescriptor =
|
||||
propertySetters(propertyDescriptor)
|
||||
}
|
||||
+43
-43
@@ -18,13 +18,17 @@ package org.jetbrains.kotlin.psi2ir.intermediate
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyGetterDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertySetterDescriptor
|
||||
import org.jetbrains.kotlin.ir.declarations.IrVariable
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.psi2ir.generators.GeneratorContext
|
||||
import org.jetbrains.kotlin.psi2ir.generators.Scope
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.utils.SmartList
|
||||
|
||||
class SimplePropertyLValue(
|
||||
val context: GeneratorContext,
|
||||
val scope: Scope,
|
||||
val startOffset: Int,
|
||||
val endOffset: Int,
|
||||
@@ -35,49 +39,45 @@ class SimplePropertyLValue(
|
||||
) : LValue, AssignmentReceiver {
|
||||
override val type: KotlinType get() = descriptor.type
|
||||
|
||||
override fun load(): IrExpression {
|
||||
val getter = descriptor.getter ?: throw AssertionError("No getter for $descriptor")
|
||||
return callReceiver.call { dispatchReceiverValue, extensionReceiverValue ->
|
||||
IrGetterCallImpl(startOffset, endOffset, getter,
|
||||
dispatchReceiverValue?.load(),
|
||||
extensionReceiverValue?.load(),
|
||||
irOperator,
|
||||
superQualifier)
|
||||
}
|
||||
}
|
||||
|
||||
override fun store(irExpression: IrExpression): IrExpression {
|
||||
val setter = descriptor.setter ?: throw AssertionError("No setter for $descriptor")
|
||||
return callReceiver.call { dispatchReceiverValue, extensionReceiverValue ->
|
||||
IrSetterCallImpl(startOffset, endOffset, setter,
|
||||
dispatchReceiverValue?.load(),
|
||||
extensionReceiverValue?.load(),
|
||||
irExpression,
|
||||
irOperator,
|
||||
superQualifier)
|
||||
}
|
||||
}
|
||||
|
||||
override fun assign(withLValue: (LValue) -> IrExpression): IrExpression {
|
||||
return callReceiver.call { dispatchReceiverValue, extensionReceiverValue ->
|
||||
val variablesForReceivers = SmartList<IrVariable>()
|
||||
|
||||
val irResultExpression = withLValue(
|
||||
SimplePropertyLValue(scope, startOffset, endOffset, irOperator, descriptor,
|
||||
SimpleCallReceiver(dispatchReceiverValue, extensionReceiverValue),
|
||||
superQualifier)
|
||||
)
|
||||
|
||||
if (variablesForReceivers.isEmpty()) {
|
||||
irResultExpression
|
||||
override fun load(): IrExpression =
|
||||
callReceiver.call { dispatchReceiverValue, extensionReceiverValue ->
|
||||
val getter = descriptor.getter ?: context.syntheticDescriptorsFactory.getOrCreatePropertyGetter(descriptor)
|
||||
IrGetterCallImpl(startOffset, endOffset, getter,
|
||||
dispatchReceiverValue?.load(),
|
||||
extensionReceiverValue?.load(),
|
||||
irOperator,
|
||||
superQualifier)
|
||||
}
|
||||
else {
|
||||
val irBlock = IrBlockImpl(startOffset, endOffset, irResultExpression.type, irOperator)
|
||||
irBlock.addAll(variablesForReceivers)
|
||||
irBlock.addStatement(irResultExpression)
|
||||
irBlock
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
override fun store(irExpression: IrExpression) =
|
||||
callReceiver.call { dispatchReceiverValue, extensionReceiverValue ->
|
||||
val setter = descriptor.setter ?: context.syntheticDescriptorsFactory.getOrCreatePropertySetter(descriptor)
|
||||
IrSetterCallImpl(startOffset, endOffset, setter,
|
||||
dispatchReceiverValue?.load(),
|
||||
extensionReceiverValue?.load(),
|
||||
irExpression,
|
||||
irOperator,
|
||||
superQualifier)
|
||||
}
|
||||
|
||||
override fun assign(withLValue: (LValue) -> IrExpression) =
|
||||
callReceiver.call { dispatchReceiverValue, extensionReceiverValue ->
|
||||
val variablesForReceivers = SmartList<IrVariable>()
|
||||
|
||||
val irResultExpression = withLValue(
|
||||
SimplePropertyLValue(context, scope, startOffset, endOffset, irOperator, descriptor,
|
||||
SimpleCallReceiver(dispatchReceiverValue, extensionReceiverValue),
|
||||
superQualifier)
|
||||
)
|
||||
|
||||
if (variablesForReceivers.isEmpty()) {
|
||||
irResultExpression
|
||||
}
|
||||
else {
|
||||
val irBlock = IrBlockImpl(startOffset, endOffset, irResultExpression.type, irOperator)
|
||||
irBlock.addAll(variablesForReceivers)
|
||||
irBlock.addStatement(irResultExpression)
|
||||
irBlock
|
||||
}
|
||||
}
|
||||
}
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* 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.descriptors
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.descriptors.PropertyAccessorDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.descriptors.impl.PropertyGetterDescriptorImpl
|
||||
import org.jetbrains.kotlin.descriptors.impl.PropertySetterDescriptorImpl
|
||||
|
||||
|
||||
interface IrSyntheticStaticPropertyAccessorDescriptor : PropertyAccessorDescriptor
|
||||
|
||||
interface IrSyntheticStaticPropertyGetterDescriptor : IrSyntheticStaticPropertyAccessorDescriptor
|
||||
|
||||
interface IrSyntheticStaticPropertySetterDescriptor : IrSyntheticStaticPropertyAccessorDescriptor
|
||||
|
||||
class IrSyntheticStaticPropertyGetterDescriptorImpl(
|
||||
correspondingProperty: PropertyDescriptor
|
||||
) : PropertyGetterDescriptorImpl(
|
||||
correspondingProperty,
|
||||
Annotations.EMPTY,
|
||||
Modality.FINAL,
|
||||
correspondingProperty.visibility,
|
||||
true, // isDefault
|
||||
false, // isExternal
|
||||
false, // isInline
|
||||
CallableMemberDescriptor.Kind.SYNTHESIZED,
|
||||
null,
|
||||
correspondingProperty.source
|
||||
), IrSyntheticStaticPropertyGetterDescriptor {
|
||||
init {
|
||||
initialize(correspondingProperty.type)
|
||||
}
|
||||
}
|
||||
|
||||
class IrSyntheticStaticPropertySetterDescriptorImpl(
|
||||
correspondingProperty: PropertyDescriptor
|
||||
) : PropertySetterDescriptorImpl(
|
||||
correspondingProperty,
|
||||
Annotations.EMPTY,
|
||||
Modality.FINAL,
|
||||
correspondingProperty.visibility,
|
||||
true, // isDefault
|
||||
false, // isExternal
|
||||
false, // isInline
|
||||
CallableMemberDescriptor.Kind.SYNTHESIZED,
|
||||
null,
|
||||
correspondingProperty.source
|
||||
), IrSyntheticStaticPropertySetterDescriptor {
|
||||
init {
|
||||
initializeDefault()
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,25 @@
|
||||
fun test1() {
|
||||
// System.out.println("test1")
|
||||
fun testFun() {
|
||||
System.out.println("testFun")
|
||||
}
|
||||
|
||||
var testProp: Any
|
||||
get() {
|
||||
System.out.println("testProp/get")
|
||||
return 42
|
||||
}
|
||||
set(value) {
|
||||
System.out.println("testProp/set")
|
||||
}
|
||||
|
||||
class TestClass {
|
||||
val test = when {
|
||||
else -> {
|
||||
System.out.println("TestClass/test")
|
||||
42
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
System.out.println("TestClass/init")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
FILE /jvmStaticFieldReference.kt
|
||||
FUN public fun testFun(): kotlin.Unit
|
||||
BLOCK_BODY
|
||||
CALL .println type=kotlin.Unit operator=null
|
||||
$this: TYPE_OP operator=IMPLICIT_NOTNULL typeOperand=java.io.PrintStream
|
||||
CALL .<get-out> type=java.io.PrintStream! operator=GET_PROPERTY
|
||||
p0: CONST String type=kotlin.String value='testFun'
|
||||
PROPERTY public var testProp: kotlin.Any getter=<get-testProp> setter=<set-testProp>
|
||||
PROPERTY_GETTER public fun <get-testProp>(): kotlin.Any property=testProp
|
||||
BLOCK_BODY
|
||||
CALL .println type=kotlin.Unit operator=null
|
||||
$this: TYPE_OP operator=IMPLICIT_NOTNULL typeOperand=java.io.PrintStream
|
||||
CALL .<get-out> type=java.io.PrintStream! operator=GET_PROPERTY
|
||||
p0: CONST String type=kotlin.String value='testProp/get'
|
||||
RETURN type=kotlin.Nothing from=<get-testProp>
|
||||
CONST Int type=kotlin.Int value='42'
|
||||
PROPERTY_SETTER public fun <set-testProp>(/*0*/ value: kotlin.Any): kotlin.Unit property=testProp
|
||||
BLOCK_BODY
|
||||
CALL .println type=kotlin.Unit operator=null
|
||||
$this: TYPE_OP operator=IMPLICIT_NOTNULL typeOperand=java.io.PrintStream
|
||||
CALL .<get-out> type=java.io.PrintStream! operator=GET_PROPERTY
|
||||
p0: CONST String type=kotlin.String value='testProp/set'
|
||||
CLASS CLASS TestClass
|
||||
FUN public constructor TestClass()
|
||||
BLOCK_BODY
|
||||
SET_BACKING_FIELD test type=kotlin.Unit operator=null
|
||||
WHEN type=kotlin.Int operator=WHEN
|
||||
else: BLOCK type=kotlin.Int operator=null
|
||||
CALL .println type=kotlin.Unit operator=null
|
||||
$this: TYPE_OP operator=IMPLICIT_NOTNULL typeOperand=java.io.PrintStream
|
||||
CALL .<get-out> type=java.io.PrintStream! operator=GET_PROPERTY
|
||||
p0: CONST String type=kotlin.String value='TestClass/test'
|
||||
CONST Int type=kotlin.Int value='42'
|
||||
BLOCK type=kotlin.Unit operator=null
|
||||
CALL .println type=kotlin.Unit operator=null
|
||||
$this: TYPE_OP operator=IMPLICIT_NOTNULL typeOperand=java.io.PrintStream
|
||||
CALL .<get-out> type=java.io.PrintStream! operator=GET_PROPERTY
|
||||
p0: CONST String type=kotlin.String value='TestClass/init'
|
||||
PROPERTY public final val test: kotlin.Int getter=null setter=null
|
||||
EXPRESSION_BODY
|
||||
WHEN type=kotlin.Int operator=WHEN
|
||||
else: BLOCK type=kotlin.Int operator=null
|
||||
CALL .println type=kotlin.Unit operator=null
|
||||
$this: TYPE_OP operator=IMPLICIT_NOTNULL typeOperand=java.io.PrintStream
|
||||
CALL .<get-out> type=java.io.PrintStream! operator=GET_PROPERTY
|
||||
p0: CONST String type=kotlin.String value='TestClass/test'
|
||||
CONST Int type=kotlin.Int value='42'
|
||||
@@ -0,0 +1 @@
|
||||
fun test() = when { else -> 42 }
|
||||
@@ -0,0 +1,6 @@
|
||||
FILE /whenElse.kt
|
||||
FUN public fun test(): kotlin.Int
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from=test
|
||||
WHEN type=kotlin.Int operator=WHEN
|
||||
else: CONST Int type=kotlin.Int value='42'
|
||||
@@ -418,6 +418,12 @@ public class IrTextTestCaseGenerated extends AbstractIrTextTestCase {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("whenElse.kt")
|
||||
public void testWhenElse() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/expressions/whenElse.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("whileDoWhile.kt")
|
||||
public void testWhileDoWhile() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/expressions/whileDoWhile.kt");
|
||||
|
||||
Reference in New Issue
Block a user