handle getters/setters without body; generate initializers for class-level properties
This commit is contained in:
@@ -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("<init>", Type.VOID_TYPE, new Type[0]);
|
||||
final MethodVisitor mv = v.visitMethod(flags, "<init>", 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, "<init>", 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);
|
||||
|
||||
@@ -60,7 +60,7 @@ public class ExpressionCodegen extends JetVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
private void genToJVMStack(JetExpression expr) {
|
||||
public void genToJVMStack(JetExpression expr) {
|
||||
gen(expr, expressionType(expr));
|
||||
}
|
||||
|
||||
|
||||
@@ -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.<ValueParameterDescriptor>emptyList());
|
||||
if (getter.getBodyExpression() != null) {
|
||||
functionCodegen.generateMethod(getter, kind, mapper.mapGetterSignature(propertyDescriptor),
|
||||
Collections.<ValueParameterDescriptor>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;
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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"));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user