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:
Dmitry Petrov
2016-08-29 20:18:42 +03:00
committed by Dmitry Petrov
parent 05b9eda809
commit b3f605c4c4
12 changed files with 263 additions and 50 deletions
@@ -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 =
@@ -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(),
@@ -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)
@@ -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)
}
@@ -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
}
}
}
@@ -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'
+1
View File
@@ -0,0 +1 @@
fun test() = when { else -> 42 }
+6
View File
@@ -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");