generate property accessors in class interface

This commit is contained in:
Dmitry Jemerov
2011-04-21 19:47:39 +02:00
parent e0eb3ebd48
commit bbf4fbc34f
2 changed files with 83 additions and 42 deletions
@@ -34,7 +34,7 @@ public class PropertyCodegen {
} }
public void genInInterface(JetProperty p) { public void genInInterface(JetProperty p) {
gen(p, OwnerKind.INTERFACE);
} }
public void genInImplementation(JetProperty p) { public void genInImplementation(JetProperty p) {
@@ -46,54 +46,88 @@ public class PropertyCodegen {
} }
public void gen(JetProperty p, OwnerKind kind) { public void gen(JetProperty p, OwnerKind kind) {
final VariableDescriptor descriptor = context.getVariableDescriptor(p);
if (!(descriptor instanceof PropertyDescriptor)) {
throw new UnsupportedOperationException("expect a property to have a property descriptor");
}
final PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor;
if (kind == OwnerKind.NAMESPACE || kind == OwnerKind.IMPLEMENTATION) { if (kind == OwnerKind.NAMESPACE || kind == OwnerKind.IMPLEMENTATION) {
final VariableDescriptor descriptor = context.getVariableDescriptor(p); generateBackingField(p, kind, propertyDescriptor);
if (!(descriptor instanceof PropertyDescriptor)) { generateGetter(p, kind, propertyDescriptor);
throw new UnsupportedOperationException("expect a property to have a property descriptor"); generateSetter(p, kind, propertyDescriptor);
} }
final PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor; else if (kind == OwnerKind.INTERFACE) {
if (context.hasBackingField(propertyDescriptor)) {
Object value = null;
final JetExpression initializer = p.getInitializer();
if (initializer != null) {
if (initializer instanceof JetConstantExpression) {
value = ((JetConstantExpression) initializer).getValue();
}
}
int modifiers = Opcodes.ACC_PRIVATE;
if (kind == OwnerKind.NAMESPACE) {
modifiers |= Opcodes.ACC_STATIC;
}
v.visitField(modifiers, p.getName(), mapper.mapType(descriptor.getOutType()).getDescriptor(), null, value);
}
final JetPropertyAccessor getter = p.getGetter(); final JetPropertyAccessor getter = p.getGetter();
if (getter != null) { if ((getter != null && !getter.hasModifier(JetTokens.PRIVATE_KEYWORD) ||
if (getter.getBodyExpression() != null) { (getter == null && isExternallyAccessible(p)))) {
functionCodegen.generateMethod(getter, kind, mapper.mapGetterSignature(propertyDescriptor), v.visitMethod(Opcodes.ACC_ABSTRACT | Opcodes.ACC_PUBLIC,
Collections.<ValueParameterDescriptor>emptyList()); getterName(p.getName()),
} mapper.mapGetterSignature(propertyDescriptor).getDescriptor(),
else if (!getter.hasModifier(JetTokens.PRIVATE_KEYWORD)) { null, null);
generateDefaultGetter(p, getter, kind);
}
}
else if (p.hasModifier(JetTokens.PUBLIC_KEYWORD)) {
generateDefaultGetter(p, p, kind);
} }
final JetPropertyAccessor setter = p.getSetter(); final JetPropertyAccessor setter = p.getSetter();
if (setter != null) { if ((setter != null && !setter.hasModifier(JetTokens.PRIVATE_KEYWORD) ||
if (setter.getBodyExpression() != null) { (setter == null && isExternallyAccessible(p) && p.isVar()))) {
final PropertySetterDescriptor setterDescriptor = propertyDescriptor.getSetter(); v.visitMethod(Opcodes.ACC_ABSTRACT | Opcodes.ACC_PUBLIC,
assert setterDescriptor != null; setterName(p.getName()),
functionCodegen.generateMethod(setter, kind, mapper.mapSetterSignature(propertyDescriptor), mapper.mapSetterSignature(propertyDescriptor).getDescriptor(),
setterDescriptor.getUnsubstitutedValueParameters()); null, null);
} }
else if (!p.hasModifier(JetTokens.PRIVATE_KEYWORD)) { }
generateDefaultSetter(p, setter, kind); }
private void generateBackingField(JetProperty p, OwnerKind kind, PropertyDescriptor propertyDescriptor) {
if (context.hasBackingField(propertyDescriptor)) {
Object value = null;
final JetExpression initializer = p.getInitializer();
if (initializer != null) {
if (initializer instanceof JetConstantExpression) {
value = ((JetConstantExpression) initializer).getValue();
} }
} }
else if (p.hasModifier(JetTokens.PUBLIC_KEYWORD) && p.isVar()) { int modifiers = Opcodes.ACC_PRIVATE;
generateDefaultSetter(p, p, kind); if (kind == OwnerKind.NAMESPACE) {
modifiers |= Opcodes.ACC_STATIC;
} }
v.visitField(modifiers, p.getName(), mapper.mapType(propertyDescriptor.getOutType()).getDescriptor(), null, value);
}
}
private void generateGetter(JetProperty p, OwnerKind kind, PropertyDescriptor propertyDescriptor) {
final JetPropertyAccessor getter = p.getGetter();
if (getter != null) {
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 (isExternallyAccessible(p)) {
generateDefaultGetter(p, p, kind);
}
}
private static boolean isExternallyAccessible(JetProperty p) {
return p.hasModifier(JetTokens.PUBLIC_KEYWORD);
}
private void generateSetter(JetProperty p, OwnerKind kind, PropertyDescriptor propertyDescriptor) {
final JetPropertyAccessor setter = p.getSetter();
if (setter != null) {
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 (isExternallyAccessible(p) && p.isVar()) {
generateDefaultSetter(p, p, kind);
} }
} }
@@ -40,6 +40,13 @@ public class PropertyGenTest extends CodegenTestCase {
assertEquals(239, ((Integer) getter.invoke(instance)).intValue()); assertEquals(239, ((Integer) getter.invoke(instance)).intValue());
} }
public void testAccessorsInInterface() {
loadText("class AccessorsInInterface { public var foo = 0; }");
final Class aClass = loadClass("AccessorsInInterface", generateClassesInFile());
assertNotNull(findMethodByName(aClass, "getFoo"));
assertNotNull(findMethodByName(aClass, "setFoo"));
}
public void testPropertyInNamespace() throws Exception { public void testPropertyInNamespace() throws Exception {
loadText("private val x = 239"); loadText("private val x = 239");
final Class nsClass = generateNamespaceClass(); final Class nsClass = generateNamespaceClass();