generate public accessor methods for public properties
This commit is contained in:
@@ -27,8 +27,6 @@ public class ExpressionCodegen extends JetVisitor {
|
||||
private static final String CLASS_STRING_BUILDER = "java/lang/StringBuilder";
|
||||
private static final String CLASS_COMPARABLE = "java/lang/Comparable";
|
||||
|
||||
private static final Type TYPE_OBJECT = Type.getObjectType(CLASS_OBJECT);
|
||||
|
||||
private final Stack<Label> myContinueTargets = new Stack<Label>();
|
||||
private final Stack<Label> myBreakTargets = new Stack<Label>();
|
||||
private final Stack<StackValue> myStack = new Stack<StackValue>();
|
||||
@@ -372,21 +370,8 @@ public class ExpressionCodegen extends JetVisitor {
|
||||
}
|
||||
else if (descriptor instanceof PropertyDescriptor) {
|
||||
final PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor;
|
||||
String owner;
|
||||
boolean isStatic;
|
||||
if (descriptor.getContainingDeclaration() instanceof NamespaceDescriptor) {
|
||||
JetNamespace ns = (JetNamespace) bindingContext.getDeclarationPsiElement(descriptor.getContainingDeclaration());
|
||||
owner = JetTypeMapper.jvmName(ns);
|
||||
isStatic = true;
|
||||
}
|
||||
else if (descriptor.getContainingDeclaration() instanceof ClassDescriptor) {
|
||||
ClassDescriptor classDescriptor = (ClassDescriptor) descriptor.getContainingDeclaration();
|
||||
owner = JetTypeMapper.jvmNameForImplementation(classDescriptor);
|
||||
isStatic = false;
|
||||
}
|
||||
else {
|
||||
throw new UnsupportedOperationException("don't know how to generate property reference with parent " + descriptor.getContainingDeclaration());
|
||||
}
|
||||
boolean isStatic = descriptor.getContainingDeclaration() instanceof NamespaceDescriptor;
|
||||
String owner = JetTypeMapper.getOwner(descriptor);
|
||||
final JetType outType = ((VariableDescriptor) descriptor).getOutType();
|
||||
Method getter;
|
||||
Method setter;
|
||||
@@ -395,8 +380,8 @@ public class ExpressionCodegen extends JetVisitor {
|
||||
setter = null;
|
||||
}
|
||||
else {
|
||||
getter = typeMapper.mapGetterSignature(propertyDescriptor);
|
||||
setter = typeMapper.mapSetterSignature(propertyDescriptor);
|
||||
getter = propertyDescriptor.getGetter() == null ? null : typeMapper.mapGetterSignature(propertyDescriptor);
|
||||
setter = propertyDescriptor.getSetter() == null ? null : typeMapper.mapSetterSignature(propertyDescriptor);
|
||||
}
|
||||
if (!isStatic) {
|
||||
ensureReceiverOnStack(expression);
|
||||
@@ -497,11 +482,11 @@ public class ExpressionCodegen extends JetVisitor {
|
||||
final JetDotQualifiedExpression parent = (JetDotQualifiedExpression) expression.getParent();
|
||||
if (!resolvesToClassOrPackage(parent.getReceiverExpression())) {
|
||||
// we have a receiver on stack
|
||||
myStack.pop().put(TYPE_OBJECT, v);
|
||||
myStack.pop().put(JetTypeMapper.TYPE_OBJECT, v);
|
||||
}
|
||||
}
|
||||
else if (!(expression.getParent() instanceof JetSafeQualifiedExpression)) {
|
||||
v.load(0, TYPE_OBJECT); // TODO hope it works; really need more checks here :)
|
||||
v.load(0, JetTypeMapper.TYPE_OBJECT); // TODO hope it works; really need more checks here :)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -856,7 +841,7 @@ public class ExpressionCodegen extends JetVisitor {
|
||||
Type exprType = expressionType(expr);
|
||||
gen(expr, exprType);
|
||||
Method appendDescriptor = new Method("append", Type.getObjectType(CLASS_STRING_BUILDER),
|
||||
new Type[] { exprType.getSort() == Type.OBJECT ? TYPE_OBJECT : exprType});
|
||||
new Type[] { exprType.getSort() == Type.OBJECT ? JetTypeMapper.TYPE_OBJECT : exprType});
|
||||
v.invokevirtual(CLASS_STRING_BUILDER, "append", appendDescriptor.getDescriptor());
|
||||
}
|
||||
|
||||
|
||||
@@ -2,14 +2,12 @@ package org.jetbrains.jet.codegen;
|
||||
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.psi.JetFunction;
|
||||
import org.jetbrains.jet.lang.psi.JetNamespace;
|
||||
import org.jetbrains.jet.lang.psi.JetParameter;
|
||||
import org.jetbrains.jet.lang.psi.JetTypeReference;
|
||||
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;
|
||||
import org.jetbrains.jet.resolve.DescriptorUtil;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.commons.Method;
|
||||
|
||||
@@ -19,6 +17,8 @@ import java.util.List;
|
||||
* @author yole
|
||||
*/
|
||||
public class JetTypeMapper {
|
||||
static final Type TYPE_OBJECT = Type.getObjectType("java/lang/Object");
|
||||
|
||||
private final JetStandardLibrary standardLibrary;
|
||||
private final BindingContext bindingContext;
|
||||
|
||||
@@ -39,6 +39,10 @@ public class JetTypeMapper {
|
||||
return NamespaceCodegen.getJVMClassName(namespace.getFQName());
|
||||
}
|
||||
|
||||
static String jvmName(NamespaceDescriptor namespace) {
|
||||
return NamespaceCodegen.getJVMClassName(DescriptorUtil.getFQName(namespace));
|
||||
}
|
||||
|
||||
public static String jvmNameForInterface(ClassDescriptor descriptor) {
|
||||
return DescriptorUtil.getFQName(descriptor).replace('.', '/');
|
||||
}
|
||||
@@ -51,6 +55,21 @@ public class JetTypeMapper {
|
||||
return jvmNameForInterface(descriptor) + "$$DImpl";
|
||||
}
|
||||
|
||||
static String getOwner(DeclarationDescriptor descriptor) {
|
||||
String owner;
|
||||
if (descriptor.getContainingDeclaration() instanceof NamespaceDescriptor) {
|
||||
owner = jvmName((NamespaceDescriptor) descriptor.getContainingDeclaration());
|
||||
}
|
||||
else if (descriptor.getContainingDeclaration() instanceof ClassDescriptor) {
|
||||
ClassDescriptor classDescriptor = (ClassDescriptor) descriptor.getContainingDeclaration();
|
||||
owner = jvmNameForImplementation(classDescriptor);
|
||||
}
|
||||
else {
|
||||
throw new UnsupportedOperationException("don't know how to generate owner for parent " + descriptor.getContainingDeclaration());
|
||||
}
|
||||
return owner;
|
||||
}
|
||||
|
||||
public Type mapType(final JetType jetType) {
|
||||
if (jetType.equals(JetStandardClasses.getUnitType())) {
|
||||
return Type.VOID_TYPE;
|
||||
@@ -150,21 +169,27 @@ public class JetTypeMapper {
|
||||
return new Method(f.getName(), returnType, parameterTypes);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Method mapGetterSignature(PropertyDescriptor descriptor) {
|
||||
if (descriptor.getGetter() == null) {
|
||||
return null;
|
||||
}
|
||||
Type returnType = mapType(descriptor.getOutType());
|
||||
return new Method(PropertyCodegen.getterName(descriptor.getName()), returnType, new Type[0]);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Method mapSetterSignature(PropertyDescriptor descriptor) {
|
||||
if (descriptor.getSetter() == null) {
|
||||
return null;
|
||||
}
|
||||
Type paramType = mapType(descriptor.getInType());
|
||||
return new Method(PropertyCodegen.setterName(descriptor.getName()), Type.VOID_TYPE, new Type[] { paramType });
|
||||
}
|
||||
|
||||
static int getAccessModifiers(JetDeclaration p, int defaultFlags) {
|
||||
int flags = 0;
|
||||
if (p.hasModifier(JetTokens.PUBLIC_KEYWORD)) {
|
||||
flags |= Opcodes.ACC_PUBLIC;
|
||||
}
|
||||
else if (p.hasModifier(JetTokens.PRIVATE_KEYWORD)) {
|
||||
flags |= Opcodes.ACC_PRIVATE;
|
||||
}
|
||||
else {
|
||||
flags |= defaultFlags;
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,8 +7,12 @@ import org.jetbrains.jet.lang.psi.JetProperty;
|
||||
import org.jetbrains.jet.lang.psi.JetPropertyAccessor;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.types.*;
|
||||
import org.jetbrains.jet.lexer.JetTokens;
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.commons.InstructionAdapter;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
@@ -63,15 +67,16 @@ public class PropertyCodegen {
|
||||
if (kind == OwnerKind.NAMESPACE) {
|
||||
modifiers |= Opcodes.ACC_STATIC;
|
||||
}
|
||||
v.visitField(modifiers, p.getName(),
|
||||
mapper.mapType(descriptor.getOutType()).getDescriptor(),
|
||||
null, value);
|
||||
v.visitField(modifiers, p.getName(), mapper.mapType(descriptor.getOutType()).getDescriptor(), null, value);
|
||||
}
|
||||
final JetPropertyAccessor getter = p.getGetter();
|
||||
if (getter != null) {
|
||||
functionCodegen.generateMethod(getter, kind, mapper.mapGetterSignature(propertyDescriptor),
|
||||
Collections.<ValueParameterDescriptor>emptyList());
|
||||
}
|
||||
else if (p.hasModifier(JetTokens.PUBLIC_KEYWORD)) {
|
||||
generateDefaultGetter(p, kind);
|
||||
}
|
||||
final JetPropertyAccessor setter = p.getSetter();
|
||||
if (setter != null) {
|
||||
final PropertySetterDescriptor setterDescriptor = propertyDescriptor.getSetter();
|
||||
@@ -79,9 +84,60 @@ public class PropertyCodegen {
|
||||
functionCodegen.generateMethod(setter, kind, mapper.mapSetterSignature(propertyDescriptor),
|
||||
setterDescriptor.getUnsubstitutedValueParameters());
|
||||
}
|
||||
else if (p.hasModifier(JetTokens.PUBLIC_KEYWORD) && p.isVar()) {
|
||||
generateDefaultSetter(p, kind);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void generateDefaultGetter(JetProperty p, OwnerKind kind) {
|
||||
final PropertyDescriptor propertyDescriptor = (PropertyDescriptor) context.getVariableDescriptor(p);
|
||||
int flags = JetTypeMapper.getAccessModifiers(p, Opcodes.ACC_PUBLIC);
|
||||
if (kind == OwnerKind.NAMESPACE) {
|
||||
flags |= Opcodes.ACC_STATIC;
|
||||
}
|
||||
final String signature = mapper.mapGetterSignature(propertyDescriptor).getDescriptor();
|
||||
MethodVisitor mv = v.visitMethod(flags, getterName(p.getName()), signature, null, null);
|
||||
mv.visitCode();
|
||||
InstructionAdapter iv = new InstructionAdapter(mv);
|
||||
if (kind != OwnerKind.NAMESPACE) {
|
||||
iv.load(0, JetTypeMapper.TYPE_OBJECT);
|
||||
}
|
||||
final Type type = mapper.mapType(propertyDescriptor.getOutType());
|
||||
iv.visitFieldInsn(kind == OwnerKind.NAMESPACE ? Opcodes.GETSTATIC : Opcodes.GETFIELD,
|
||||
JetTypeMapper.getOwner(propertyDescriptor), propertyDescriptor.getName(),
|
||||
type.getDescriptor());
|
||||
iv.areturn(type);
|
||||
mv.visitMaxs(0, 0);
|
||||
mv.visitEnd();
|
||||
}
|
||||
|
||||
private void generateDefaultSetter(JetProperty p, OwnerKind kind) {
|
||||
final PropertyDescriptor propertyDescriptor = (PropertyDescriptor) context.getVariableDescriptor(p);
|
||||
int flags = JetTypeMapper.getAccessModifiers(p, Opcodes.ACC_PUBLIC);
|
||||
if (kind == OwnerKind.NAMESPACE) {
|
||||
flags |= Opcodes.ACC_STATIC;
|
||||
}
|
||||
final String signature = mapper.mapSetterSignature(propertyDescriptor).getDescriptor();
|
||||
MethodVisitor mv = v.visitMethod(flags, setterName(p.getName()), signature, null, null);
|
||||
mv.visitCode();
|
||||
InstructionAdapter iv = new InstructionAdapter(mv);
|
||||
final Type type = mapper.mapType(propertyDescriptor.getOutType());
|
||||
if (kind != OwnerKind.NAMESPACE) {
|
||||
iv.load(0, JetTypeMapper.TYPE_OBJECT);
|
||||
iv.load(1, type);
|
||||
}
|
||||
else {
|
||||
iv.load(0, type);
|
||||
}
|
||||
iv.visitFieldInsn(kind == OwnerKind.NAMESPACE ? Opcodes.PUTSTATIC : Opcodes.PUTFIELD,
|
||||
JetTypeMapper.getOwner(propertyDescriptor), propertyDescriptor.getName(),
|
||||
type.getDescriptor());
|
||||
iv.visitInsn(Opcodes.RETURN);
|
||||
mv.visitMaxs(0, 0);
|
||||
mv.visitEnd();
|
||||
}
|
||||
|
||||
public static String getterName(String propertyName) {
|
||||
return "get" + StringUtil.capitalizeWithJavaBeanConvention(propertyName);
|
||||
}
|
||||
|
||||
@@ -29,6 +29,17 @@ public class PropertyGenTest extends CodegenTestCase {
|
||||
assertEquals(239, ((Integer) getter.invoke(instance)).intValue());
|
||||
}
|
||||
|
||||
public void testPublicVar() throws Exception {
|
||||
loadText("class PublicVar { public var foo = 0; }");
|
||||
System.out.println(generateToText());
|
||||
final Class aClass = loadImplementationClass(generateClassesInFile(), "PublicVar");
|
||||
final Object instance = aClass.newInstance();
|
||||
Method setter = findMethodByName(aClass, "setFoo");
|
||||
setter.invoke(instance, 239);
|
||||
Method getter = findMethodByName(aClass, "getFoo");
|
||||
assertEquals(239, ((Integer) getter.invoke(instance)).intValue());
|
||||
}
|
||||
|
||||
public void testPropertyInNamespace() throws Exception {
|
||||
loadText("private val x = 239");
|
||||
final Class nsClass = generateNamespaceClass();
|
||||
|
||||
Reference in New Issue
Block a user