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.ClassDescriptor;
|
||||||
import org.jetbrains.jet.lang.types.JetStandardLibrary;
|
import org.jetbrains.jet.lang.types.JetStandardLibrary;
|
||||||
import org.jetbrains.jet.lang.types.JetType;
|
import org.jetbrains.jet.lang.types.JetType;
|
||||||
|
import org.jetbrains.jet.lang.types.PropertyDescriptor;
|
||||||
import org.objectweb.asm.ClassVisitor;
|
import org.objectweb.asm.ClassVisitor;
|
||||||
import org.objectweb.asm.MethodVisitor;
|
import org.objectweb.asm.MethodVisitor;
|
||||||
import org.objectweb.asm.Opcodes;
|
import org.objectweb.asm.Opcodes;
|
||||||
@@ -161,15 +162,44 @@ public class ClassCodegen {
|
|||||||
Method method = new Method("<init>", Type.VOID_TYPE, new Type[0]);
|
Method method = new Method("<init>", Type.VOID_TYPE, new Type[0]);
|
||||||
final MethodVisitor mv = v.visitMethod(flags, "<init>", method.getDescriptor(), null, null);
|
final MethodVisitor mv = v.visitMethod(flags, "<init>", method.getDescriptor(), null, null);
|
||||||
mv.visitCode();
|
mv.visitCode();
|
||||||
|
|
||||||
|
FrameMap frameMap = new FrameMap();
|
||||||
|
frameMap.enterTemp(); // this
|
||||||
|
|
||||||
final InstructionAdapter iv = new InstructionAdapter(mv);
|
final InstructionAdapter iv = new InstructionAdapter(mv);
|
||||||
String superClass = getSuperClass(aClass, kind);
|
String superClass = getSuperClass(aClass, kind);
|
||||||
iv.load(0, Type.getType("L" + superClass + ";"));
|
iv.load(0, Type.getType("L" + superClass + ";"));
|
||||||
iv.invokespecial(superClass, "<init>", method.getDescriptor());
|
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);
|
iv.visitInsn(Opcodes.RETURN);
|
||||||
mv.visitMaxs(0, 0);
|
mv.visitMaxs(0, 0);
|
||||||
mv.visitEnd();
|
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) {
|
private void generateClassBody(JetClass aClass, ClassVisitor v, OwnerKind kind) {
|
||||||
final JetStandardLibrary standardLibrary = JetStandardLibrary.getJetStandardLibrary(project);
|
final JetStandardLibrary standardLibrary = JetStandardLibrary.getJetStandardLibrary(project);
|
||||||
final FunctionCodegen functionCodegen = new FunctionCodegen(v, standardLibrary, bindingContext);
|
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));
|
gen(expr, expressionType(expr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,7 @@
|
|||||||
package org.jetbrains.jet.codegen;
|
package org.jetbrains.jet.codegen;
|
||||||
|
|
||||||
import com.intellij.openapi.util.text.StringUtil;
|
import com.intellij.openapi.util.text.StringUtil;
|
||||||
import org.jetbrains.jet.lang.psi.JetConstantExpression;
|
import org.jetbrains.jet.lang.psi.*;
|
||||||
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.resolve.BindingContext;
|
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||||
import org.jetbrains.jet.lang.types.*;
|
import org.jetbrains.jet.lang.types.*;
|
||||||
import org.jetbrains.jet.lexer.JetTokens;
|
import org.jetbrains.jet.lexer.JetTokens;
|
||||||
@@ -71,28 +68,38 @@ public class PropertyCodegen {
|
|||||||
}
|
}
|
||||||
final JetPropertyAccessor getter = p.getGetter();
|
final JetPropertyAccessor getter = p.getGetter();
|
||||||
if (getter != null) {
|
if (getter != null) {
|
||||||
functionCodegen.generateMethod(getter, kind, mapper.mapGetterSignature(propertyDescriptor),
|
if (getter.getBodyExpression() != null) {
|
||||||
Collections.<ValueParameterDescriptor>emptyList());
|
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)) {
|
else if (p.hasModifier(JetTokens.PUBLIC_KEYWORD)) {
|
||||||
generateDefaultGetter(p, kind);
|
generateDefaultGetter(p, p, kind);
|
||||||
}
|
}
|
||||||
final JetPropertyAccessor setter = p.getSetter();
|
final JetPropertyAccessor setter = p.getSetter();
|
||||||
if (setter != null) {
|
if (setter != null) {
|
||||||
final PropertySetterDescriptor setterDescriptor = propertyDescriptor.getSetter();
|
if (setter.getBodyExpression() != null) {
|
||||||
assert setterDescriptor != null;
|
final PropertySetterDescriptor setterDescriptor = propertyDescriptor.getSetter();
|
||||||
functionCodegen.generateMethod(setter, kind, mapper.mapSetterSignature(propertyDescriptor),
|
assert setterDescriptor != null;
|
||||||
setterDescriptor.getUnsubstitutedValueParameters());
|
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()) {
|
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);
|
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) {
|
if (kind == OwnerKind.NAMESPACE) {
|
||||||
flags |= Opcodes.ACC_STATIC;
|
flags |= Opcodes.ACC_STATIC;
|
||||||
}
|
}
|
||||||
@@ -112,9 +119,9 @@ public class PropertyCodegen {
|
|||||||
mv.visitEnd();
|
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);
|
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) {
|
if (kind == OwnerKind.NAMESPACE) {
|
||||||
flags |= Opcodes.ACC_STATIC;
|
flags |= Opcodes.ACC_STATIC;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package org.jetbrains.jet.codegen;
|
|||||||
import com.intellij.testFramework.LightProjectDescriptor;
|
import com.intellij.testFramework.LightProjectDescriptor;
|
||||||
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
|
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.jet.JetLightProjectDescriptor;
|
import org.jetbrains.jet.JetLightProjectDescriptor;
|
||||||
import org.jetbrains.jet.lang.JetFileType;
|
import org.jetbrains.jet.lang.JetFileType;
|
||||||
import org.jetbrains.jet.lang.psi.JetFile;
|
import org.jetbrains.jet.lang.psi.JetFile;
|
||||||
@@ -97,16 +98,21 @@ public abstract class CodegenTestCase extends LightCodeInsightFixtureTestCase {
|
|||||||
|
|
||||||
protected Method generateFunction(String name) {
|
protected Method generateFunction(String name) {
|
||||||
Class aClass = generateNamespaceClass();
|
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) {
|
protected static Method findMethodByName(Class aClass, String name) {
|
||||||
for (Method method : aClass.getMethods()) {
|
for (Method method : aClass.getMethods()) {
|
||||||
if (method.getName().equals(name)) {
|
if (method.getName().equals(name)) {
|
||||||
return method;
|
return method;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw new IllegalArgumentException("couldn't find method " + name);
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static void assertIsCurrentTime(long returnValue) {
|
protected static void assertIsCurrentTime(long returnValue) {
|
||||||
|
|||||||
@@ -73,4 +73,13 @@ public class PropertyGenTest extends CodegenTestCase {
|
|||||||
String value = (String) method.invoke(null, "IDEA");
|
String value = (String) method.invoke(null, "IDEA");
|
||||||
assertEquals(value, "IntelliJ 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