From 85f46abcd2b73c3c7f5ed61d3bdb414064759bbf Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Thu, 21 Apr 2011 18:42:30 +0200 Subject: [PATCH] handle getters/setters without body; generate initializers for class-level properties --- .../jetbrains/jet/codegen/ClassCodegen.java | 30 ++++++++++++++ .../jet/codegen/ExpressionCodegen.java | 2 +- .../jet/codegen/PropertyCodegen.java | 39 +++++++++++-------- .../jet/codegen/CodegenTestCase.java | 10 ++++- .../jet/codegen/PropertyGenTest.java | 9 +++++ 5 files changed, 71 insertions(+), 19 deletions(-) diff --git a/idea/src/org/jetbrains/jet/codegen/ClassCodegen.java b/idea/src/org/jetbrains/jet/codegen/ClassCodegen.java index ee2c38710ef..6c0b10e9afb 100644 --- a/idea/src/org/jetbrains/jet/codegen/ClassCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ClassCodegen.java @@ -8,6 +8,7 @@ import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.types.ClassDescriptor; import org.jetbrains.jet.lang.types.JetStandardLibrary; import org.jetbrains.jet.lang.types.JetType; +import org.jetbrains.jet.lang.types.PropertyDescriptor; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; @@ -161,15 +162,44 @@ public class ClassCodegen { Method method = new Method("", Type.VOID_TYPE, new Type[0]); final MethodVisitor mv = v.visitMethod(flags, "", method.getDescriptor(), null, null); mv.visitCode(); + + FrameMap frameMap = new FrameMap(); + frameMap.enterTemp(); // this + final InstructionAdapter iv = new InstructionAdapter(mv); String superClass = getSuperClass(aClass, kind); iv.load(0, Type.getType("L" + superClass + ";")); iv.invokespecial(superClass, "", method.getDescriptor()); + + final JetStandardLibrary standardLibrary = JetStandardLibrary.getJetStandardLibrary(project); + final JetTypeMapper typeMapper = new JetTypeMapper(standardLibrary, bindingContext); + ExpressionCodegen codegen = new ExpressionCodegen(mv, bindingContext, frameMap, + typeMapper, Type.VOID_TYPE); + generateInitializers(aClass, kind, codegen, iv, typeMapper); + iv.visitInsn(Opcodes.RETURN); mv.visitMaxs(0, 0); mv.visitEnd(); } + private void generateInitializers(JetClass aClass, OwnerKind kind, ExpressionCodegen codegen, InstructionAdapter iv, JetTypeMapper typeMapper) { + for (JetDeclaration declaration : aClass.getDeclarations()) { + if (declaration instanceof JetProperty) { + final PropertyDescriptor propertyDescriptor = (PropertyDescriptor) bindingContext.getVariableDescriptor((JetProperty) declaration); + if (bindingContext.hasBackingField(propertyDescriptor)) { + final JetExpression initializer = ((JetProperty) declaration).getInitializer(); + if (initializer != null) { + iv.load(0, JetTypeMapper.TYPE_OBJECT); + codegen.genToJVMStack(initializer); + iv.putfield(JetTypeMapper.getOwner(propertyDescriptor), propertyDescriptor.getName(), + typeMapper.mapType(propertyDescriptor.getOutType()).getDescriptor()); + } + + } + } + } + } + private void generateClassBody(JetClass aClass, ClassVisitor v, OwnerKind kind) { final JetStandardLibrary standardLibrary = JetStandardLibrary.getJetStandardLibrary(project); final FunctionCodegen functionCodegen = new FunctionCodegen(v, standardLibrary, bindingContext); diff --git a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index cf9583d9cd5..0abae876181 100644 --- a/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -60,7 +60,7 @@ public class ExpressionCodegen extends JetVisitor { } } - private void genToJVMStack(JetExpression expr) { + public void genToJVMStack(JetExpression expr) { gen(expr, expressionType(expr)); } diff --git a/idea/src/org/jetbrains/jet/codegen/PropertyCodegen.java b/idea/src/org/jetbrains/jet/codegen/PropertyCodegen.java index 5297d9a1959..eb3c8d5c942 100644 --- a/idea/src/org/jetbrains/jet/codegen/PropertyCodegen.java +++ b/idea/src/org/jetbrains/jet/codegen/PropertyCodegen.java @@ -1,10 +1,7 @@ package org.jetbrains.jet.codegen; import com.intellij.openapi.util.text.StringUtil; -import org.jetbrains.jet.lang.psi.JetConstantExpression; -import org.jetbrains.jet.lang.psi.JetExpression; -import org.jetbrains.jet.lang.psi.JetProperty; -import org.jetbrains.jet.lang.psi.JetPropertyAccessor; +import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.types.*; import org.jetbrains.jet.lexer.JetTokens; @@ -71,28 +68,38 @@ public class PropertyCodegen { } final JetPropertyAccessor getter = p.getGetter(); if (getter != null) { - functionCodegen.generateMethod(getter, kind, mapper.mapGetterSignature(propertyDescriptor), - Collections.emptyList()); + if (getter.getBodyExpression() != null) { + functionCodegen.generateMethod(getter, kind, mapper.mapGetterSignature(propertyDescriptor), + Collections.emptyList()); + } + else if (!getter.hasModifier(JetTokens.PRIVATE_KEYWORD)) { + generateDefaultGetter(p, getter, kind); + } } else if (p.hasModifier(JetTokens.PUBLIC_KEYWORD)) { - generateDefaultGetter(p, kind); + generateDefaultGetter(p, p, kind); } final JetPropertyAccessor setter = p.getSetter(); if (setter != null) { - final PropertySetterDescriptor setterDescriptor = propertyDescriptor.getSetter(); - assert setterDescriptor != null; - functionCodegen.generateMethod(setter, kind, mapper.mapSetterSignature(propertyDescriptor), - setterDescriptor.getUnsubstitutedValueParameters()); + if (setter.getBodyExpression() != null) { + final PropertySetterDescriptor setterDescriptor = propertyDescriptor.getSetter(); + assert setterDescriptor != null; + functionCodegen.generateMethod(setter, kind, mapper.mapSetterSignature(propertyDescriptor), + setterDescriptor.getUnsubstitutedValueParameters()); + } + else if (!p.hasModifier(JetTokens.PRIVATE_KEYWORD)) { + generateDefaultSetter(p, setter, kind); + } } else if (p.hasModifier(JetTokens.PUBLIC_KEYWORD) && p.isVar()) { - generateDefaultSetter(p, kind); + generateDefaultSetter(p, p, kind); } } } - private void generateDefaultGetter(JetProperty p, OwnerKind kind) { + private void generateDefaultGetter(JetProperty p, JetDeclaration declaration, OwnerKind kind) { final PropertyDescriptor propertyDescriptor = (PropertyDescriptor) context.getVariableDescriptor(p); - int flags = JetTypeMapper.getAccessModifiers(p, Opcodes.ACC_PUBLIC); + int flags = JetTypeMapper.getAccessModifiers(declaration, Opcodes.ACC_PUBLIC); if (kind == OwnerKind.NAMESPACE) { flags |= Opcodes.ACC_STATIC; } @@ -112,9 +119,9 @@ public class PropertyCodegen { mv.visitEnd(); } - private void generateDefaultSetter(JetProperty p, OwnerKind kind) { + private void generateDefaultSetter(JetProperty p, JetDeclaration declaration, OwnerKind kind) { final PropertyDescriptor propertyDescriptor = (PropertyDescriptor) context.getVariableDescriptor(p); - int flags = JetTypeMapper.getAccessModifiers(p, Opcodes.ACC_PUBLIC); + int flags = JetTypeMapper.getAccessModifiers(declaration, Opcodes.ACC_PUBLIC); if (kind == OwnerKind.NAMESPACE) { flags |= Opcodes.ACC_STATIC; } diff --git a/idea/tests/org/jetbrains/jet/codegen/CodegenTestCase.java b/idea/tests/org/jetbrains/jet/codegen/CodegenTestCase.java index a62c81fc4a0..ede78f23acd 100644 --- a/idea/tests/org/jetbrains/jet/codegen/CodegenTestCase.java +++ b/idea/tests/org/jetbrains/jet/codegen/CodegenTestCase.java @@ -3,6 +3,7 @@ package org.jetbrains.jet.codegen; import com.intellij.testFramework.LightProjectDescriptor; import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.JetLightProjectDescriptor; import org.jetbrains.jet.lang.JetFileType; import org.jetbrains.jet.lang.psi.JetFile; @@ -97,16 +98,21 @@ public abstract class CodegenTestCase extends LightCodeInsightFixtureTestCase { protected Method generateFunction(String name) { Class aClass = generateNamespaceClass(); - return findMethodByName(aClass, name); + final Method method = findMethodByName(aClass, name); + if (method == null) { + throw new IllegalArgumentException("couldn't find method " + name); + } + return method; } + @Nullable protected static Method findMethodByName(Class aClass, String name) { for (Method method : aClass.getMethods()) { if (method.getName().equals(name)) { return method; } } - throw new IllegalArgumentException("couldn't find method " + name); + return null; } protected static void assertIsCurrentTime(long returnValue) { diff --git a/idea/tests/org/jetbrains/jet/codegen/PropertyGenTest.java b/idea/tests/org/jetbrains/jet/codegen/PropertyGenTest.java index d71b5bf43ec..ddd812664f7 100644 --- a/idea/tests/org/jetbrains/jet/codegen/PropertyGenTest.java +++ b/idea/tests/org/jetbrains/jet/codegen/PropertyGenTest.java @@ -73,4 +73,13 @@ public class PropertyGenTest extends CodegenTestCase { String value = (String) method.invoke(null, "IDEA"); assertEquals(value, "IntelliJ IDEA"); } + + public void testAccessorsWithoutBody() throws Exception { + loadText("class AccessorsWithoutBody { public var foo: Int = 349\n get\n private set } "); + final Class aClass = loadImplementationClass(generateClassesInFile(), "AccessorsWithoutBody"); + final Object instance = aClass.newInstance(); + final Method getFoo = findMethodByName(aClass, "getFoo"); + assertEquals(349, getFoo.invoke(instance)); + assertNull(findMethodByName(aClass, "setFoo")); + } }