Write KotlinSyntheticClass to anonymous and local classes

This commit is contained in:
Alexander Udalov
2014-03-05 20:30:39 +04:00
parent cbfb626d50
commit 0b2c832343
7 changed files with 55 additions and 5 deletions
@@ -35,7 +35,6 @@ import java.util.List;
import static org.jetbrains.asm4.Opcodes.ACC_STATIC;
import static org.jetbrains.asm4.Opcodes.RETURN;
import static org.jetbrains.jet.codegen.binding.CodegenBinding.enumEntryNeedSubclass;
import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isTopLevelOrInnerClass;
public abstract class ClassBodyCodegen extends MemberCodegen {
protected final JetClassOrObject myClass;
@@ -70,9 +69,7 @@ public abstract class ClassBodyCodegen extends MemberCodegen {
generateStaticInitializer();
if (state.getClassBuilderMode() == ClassBuilderMode.FULL && isTopLevelOrInnerClass(descriptor)) {
generateKotlinAnnotation();
}
generateKotlinAnnotation();
}
protected abstract void generateDeclaration();
@@ -70,6 +70,7 @@ import static org.jetbrains.jet.lang.resolve.BindingContextUtils.descriptorToDec
import static org.jetbrains.jet.lang.resolve.DescriptorUtils.*;
import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.JAVA_STRING_TYPE;
import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.OBJECT_TYPE;
import static org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames.KotlinSyntheticClass;
public class ImplementationBodyCodegen extends ClassBodyCodegen {
private static final String VALUES = "$VALUES";
@@ -209,6 +210,19 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
@Override
protected void generateKotlinAnnotation() {
if (isAnonymousObject(descriptor)) {
writeKotlinSyntheticClassAnnotation(v, KotlinSyntheticClass.Kind.ANONYMOUS_OBJECT);
return;
}
if (!isTopLevelOrInnerClass(descriptor)) {
// LOCAL_CLASS is also written to inner classes of local classes
writeKotlinSyntheticClassAnnotation(v, KotlinSyntheticClass.Kind.LOCAL_CLASS);
return;
}
if (state.getClassBuilderMode() != ClassBuilderMode.FULL) return;
DescriptorSerializer serializer = new DescriptorSerializer(new JavaSerializerExtension(v.getSerializationBindings()));
ProtoBuf.Class classProto = serializer.classProto(descriptor).build();
@@ -21,6 +21,7 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.codegen.context.ClassContext;
import org.jetbrains.jet.codegen.state.GenerationState;
import org.jetbrains.jet.lang.psi.JetClassOrObject;
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
import static org.jetbrains.asm4.Opcodes.*;
import static org.jetbrains.jet.codegen.AsmUtil.writeKotlinSyntheticClassAnnotation;
@@ -52,6 +53,10 @@ public class TraitImplBodyCodegen extends ClassBodyCodegen {
@Override
protected void generateKotlinAnnotation() {
writeKotlinSyntheticClassAnnotation(v, KotlinSyntheticClass.Kind.TRAIT_IMPL);
// We write LOCAL_CLASS to local trait-impl, because we don't want PSI classes to be constructed for such files
// (currently PSI for synthetic class is built only if this class is a trait-impl, see DecompiledUtils.kt)
writeKotlinSyntheticClassAnnotation(v, DescriptorUtils.isTopLevelOrInnerClass(descriptor)
? KotlinSyntheticClass.Kind.TRAIT_IMPL
: KotlinSyntheticClass.Kind.LOCAL_CLASS);
}
}
@@ -120,6 +120,10 @@ public class LambdaTransformer {
superName,
interfaces
);
// TODO: load synthetic class kind from the transformed class and write the same kind to the copy of that class here
// See AsmUtil.writeKotlinSyntheticClassAnnotation
ParametersBuilder builder = ParametersBuilder.newBuilder();
Parameters parameters = getLambdaParameters(builder, invocation);
@@ -84,6 +84,30 @@ public class KotlinSyntheticClassAnnotationTest extends CodegenTestCase {
ANONYMOUS_FUNCTION);
}
public void testLocalClass() {
doTest("fun foo() { class Local }",
"Local",
LOCAL_CLASS);
}
public void testLocalTraitImpl() {
doTest("fun foo() { trait Local { fun bar() = 42 } }",
"Local",
LOCAL_CLASS);
}
public void testInnerClassOfLocalClass() {
doTest("fun foo() { class Local { inner class Inner } }",
"Inner",
LOCAL_CLASS);
}
public void testAnonymousObject() {
doTest("val o = object {}",
"$",
ANONYMOUS_OBJECT);
}
private void doTest(@NotNull String code, @NotNull final String classNamePart, @NotNull KotlinSyntheticClass.Kind expectedKind) {
loadText("package " + PACKAGE_NAME + "\n\n" + code);
List<OutputFile> output = generateClassesInFile().asList();
@@ -55,6 +55,8 @@ public final class JvmAnnotationNames {
CALLABLE_REFERENCE_WRAPPER,
LOCAL_FUNCTION,
ANONYMOUS_FUNCTION,
LOCAL_CLASS,
ANONYMOUS_OBJECT,
;
@Nullable
@@ -25,6 +25,8 @@ public @interface KotlinSyntheticClass {
Kind kind();
// Inner classes of local classes have kind LOCAL_CLASS
// Local trait-impl also has kind LOCAL_CLASS
public static enum Kind {
PACKAGE_PART,
TRAIT_IMPL,
@@ -33,5 +35,7 @@ public @interface KotlinSyntheticClass {
CALLABLE_REFERENCE_WRAPPER,
LOCAL_FUNCTION,
ANONYMOUS_FUNCTION,
LOCAL_CLASS,
ANONYMOUS_OBJECT,
}
}