From cbfb626d504186c26b9c9fbb07b801ffbdf52e8d Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Wed, 5 Mar 2014 18:07:54 +0400 Subject: [PATCH] Write KotlinSyntheticClass to generated classes for functions That is SAM wrappers, callable reference wrappers, local functions and anonymous functions --- .../org/jetbrains/jet/codegen/AsmUtil.java | 2 +- .../jetbrains/jet/codegen/ClosureCodegen.java | 6 ++ .../jet/codegen/ExpressionCodegen.java | 64 +++++++------ .../jet/codegen/SamWrapperCodegen.java | 4 + .../KotlinSyntheticClassAnnotationTest.java | 95 +++++++++++++------ .../lang/resolve/java/JvmAnnotationNames.java | 22 ++++- .../kotlin/header/KotlinClassHeader.java | 25 ++++- ...eadKotlinClassHeaderAnnotationVisitor.java | 49 ++++------ .../jvm/internal/KotlinSyntheticClass.java | 7 +- .../jet/plugin/libraries/DecompiledUtils.kt | 7 +- 10 files changed, 180 insertions(+), 101 deletions(-) diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/AsmUtil.java b/compiler/backend/src/org/jetbrains/jet/codegen/AsmUtil.java index 4b4b4d6532a..a3f45a727b4 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/AsmUtil.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/AsmUtil.java @@ -665,7 +665,7 @@ public class AsmUtil { } public static void writeKotlinSyntheticClassAnnotation(@NotNull ClassBuilder v, @NotNull KotlinSyntheticClass.Kind kind) { - AnnotationVisitor av = v.newAnnotation(Type.getObjectType(KotlinSyntheticClass.INTERNAL_NAME).getDescriptor(), true); + AnnotationVisitor av = v.newAnnotation(Type.getObjectType(KotlinSyntheticClass.CLASS_NAME.getInternalName()).getDescriptor(), true); av.visit(ABI_VERSION_FIELD_NAME, JvmAbi.VERSION); av.visitEnum(KotlinSyntheticClass.KIND_FIELD_NAME.asString(), Type.getObjectType(KotlinSyntheticClass.KIND_INTERNAL_NAME).getDescriptor(), diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java index 744b273d320..f0bfd87fe3b 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java @@ -48,6 +48,7 @@ import static org.jetbrains.asm4.Opcodes.*; import static org.jetbrains.jet.codegen.AsmUtil.*; import static org.jetbrains.jet.codegen.CodegenUtil.isConst; import static org.jetbrains.jet.codegen.binding.CodegenBinding.*; +import static org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames.KotlinSyntheticClass; public class ClosureCodegen extends ParentCodegenAwareImpl { private final PsiElement fun; @@ -59,6 +60,7 @@ public class ClosureCodegen extends ParentCodegenAwareImpl { private final CalculatedClosure closure; private final Type asmType; private final int visibilityFlag; + private final KotlinSyntheticClass.Kind syntheticClassKind; private Method constructor; @@ -69,6 +71,7 @@ public class ClosureCodegen extends ParentCodegenAwareImpl { @Nullable ClassDescriptor samInterface, @NotNull Type closureSuperClass, @NotNull CodegenContext parentContext, + @NotNull KotlinSyntheticClass.Kind syntheticClassKind, @NotNull LocalLookup localLookup, @NotNull FunctionGenerationStrategy strategy, @Nullable MemberCodegen parentCodegen @@ -80,6 +83,7 @@ public class ClosureCodegen extends ParentCodegenAwareImpl { this.samInterface = samInterface; this.superClass = closureSuperClass; this.context = parentContext.intoClosure(funDescriptor, localLookup, typeMapper); + this.syntheticClassKind = syntheticClassKind; this.strategy = strategy; ClassDescriptor classDescriptor = anonymousClassForFunction(bindingContext, funDescriptor); @@ -121,6 +125,8 @@ public class ClosureCodegen extends ParentCodegenAwareImpl { ); cv.visitSource(fun.getContainingFile().getName(), null); + writeKotlinSyntheticClassAnnotation(cv, syntheticClassKind); + JvmMethodSignature jvmMethodSignature = typeMapper.mapSignature(funDescriptor).replaceName(interfaceFunction.getName().toString()); generateBridge(cv, typeMapper.mapSignature(interfaceFunction).getAsmMethod(), jvmMethodSignature.getAsmMethod()); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 970d37f52aa..abbe9b9aeb6 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -76,6 +76,7 @@ import static org.jetbrains.jet.codegen.binding.CodegenBinding.*; import static org.jetbrains.jet.lang.resolve.BindingContext.*; import static org.jetbrains.jet.lang.resolve.BindingContextUtils.getNotNull; import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.*; +import static org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames.KotlinSyntheticClass; import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue.NO_RECEIVER; public class ExpressionCodegen extends JetVisitor implements LocalLookup, ParentCodegenAware { @@ -1288,7 +1289,7 @@ public class ExpressionCodegen extends JetVisitor implem return StackValue.none(); } - StackValue closure = genClosure(function, null); + StackValue closure = genClosure(function, null, KotlinSyntheticClass.Kind.LOCAL_FUNCTION); DeclarationDescriptor descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, function); int index = lookupLocalIndex(descriptor); closure.put(OBJECT_TYPE, v); @@ -1304,18 +1305,23 @@ public class ExpressionCodegen extends JetVisitor implem return gen(expression.getFunctionLiteral().getBodyExpression()); } else { - return genClosure(expression.getFunctionLiteral(), null); + return genClosure(expression.getFunctionLiteral(), null, KotlinSyntheticClass.Kind.ANONYMOUS_FUNCTION); } } - private StackValue genClosure(JetDeclarationWithBody declaration, @Nullable ClassDescriptor samInterfaceClass) { + @NotNull + private StackValue genClosure( + JetDeclarationWithBody declaration, + @Nullable ClassDescriptor samInterfaceClass, + @NotNull KotlinSyntheticClass.Kind kind + ) { FunctionDescriptor descriptor = bindingContext.get(BindingContext.FUNCTION, declaration); assert descriptor != null : "Function is not resolved to descriptor: " + declaration.getText(); Type closureSuperClass = samInterfaceClass == null ? getFunctionImplType(descriptor) : OBJECT_TYPE; ClosureCodegen closureCodegen = new ClosureCodegen(state, declaration, descriptor, samInterfaceClass, closureSuperClass, context, - this, new FunctionGenerationStrategy.FunctionDefault(state, descriptor, declaration), parentCodegen); + kind, this, new FunctionGenerationStrategy.FunctionDefault(state, descriptor, declaration), parentCodegen); closureCodegen.gen(); @@ -1934,42 +1940,43 @@ public class ExpressionCodegen extends JetVisitor implem return genSamInterfaceValue(argumentExpression, samInterface, this); } + @NotNull private StackValue genSamInterfaceValue( @NotNull JetExpression expression, @NotNull JavaClassDescriptor samInterface, @NotNull JetVisitor visitor ) { if (expression instanceof JetFunctionLiteralExpression) { - return genClosure(((JetFunctionLiteralExpression) expression).getFunctionLiteral(), samInterface); + return genClosure(((JetFunctionLiteralExpression) expression).getFunctionLiteral(), samInterface, + KotlinSyntheticClass.Kind.SAM_LAMBDA); } - else { - Type asmType = state.getSamWrapperClasses().getSamWrapperClass(samInterface, (JetFile) expression.getContainingFile()); - v.anew(asmType); - v.dup(); + Type asmType = state.getSamWrapperClasses().getSamWrapperClass(samInterface, (JetFile) expression.getContainingFile()); - @SuppressWarnings("ConstantConditions") - Type functionType = typeMapper.mapType(samInterface.getFunctionTypeForSamInterface()); - expression.accept(visitor, StackValue.none()).put(functionType, v); + v.anew(asmType); + v.dup(); - Label ifNonNull = new Label(); - Label afterAll = new Label(); + @SuppressWarnings("ConstantConditions") + Type functionType = typeMapper.mapType(samInterface.getFunctionTypeForSamInterface()); + expression.accept(visitor, StackValue.none()).put(functionType, v); - v.dup(); - v.ifnonnull(ifNonNull); + Label ifNonNull = new Label(); + Label afterAll = new Label(); - // if null: pop function value and wrapper objects, put null - v.pop(); - v.pop2(); - v.aconst(null); - v.goTo(afterAll); + v.dup(); + v.ifnonnull(ifNonNull); - v.mark(ifNonNull); - v.invokespecial(asmType.getInternalName(), "", Type.getMethodDescriptor(Type.VOID_TYPE, functionType)); + // if null: pop function value and wrapper objects, put null + v.pop(); + v.pop2(); + v.aconst(null); + v.goTo(afterAll); - v.mark(afterAll); - return StackValue.onStack(asmType); - } + v.mark(ifNonNull); + v.invokespecial(asmType.getInternalName(), "", Type.getMethodDescriptor(Type.VOID_TYPE, functionType)); + + v.mark(afterAll); + return StackValue.onStack(asmType); } @NotNull @@ -2456,8 +2463,9 @@ public class ExpressionCodegen extends JetVisitor implem Type closureSuperClass = typeMapper.mapType(kFunctionImpl); CallableReferenceGenerationStrategy strategy = new CallableReferenceGenerationStrategy(state, functionDescriptor, resolvedCall); - ClosureCodegen closureCodegen = new ClosureCodegen(state, expression, functionDescriptor, null, closureSuperClass, context, this, - strategy, getParentCodegen()); + ClosureCodegen closureCodegen = new ClosureCodegen(state, expression, functionDescriptor, null, closureSuperClass, context, + KotlinSyntheticClass.Kind.CALLABLE_REFERENCE_WRAPPER, + this, strategy, getParentCodegen()); closureCodegen.gen(); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/SamWrapperCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/SamWrapperCodegen.java index cbb55a72b3a..bfea6c041a6 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/SamWrapperCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/SamWrapperCodegen.java @@ -38,7 +38,9 @@ import org.jetbrains.jet.lang.types.JetType; import static org.jetbrains.asm4.Opcodes.*; import static org.jetbrains.jet.codegen.AsmUtil.NO_FLAG_PACKAGE_PRIVATE; +import static org.jetbrains.jet.codegen.AsmUtil.writeKotlinSyntheticClassAnnotation; import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.OBJECT_TYPE; +import static org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames.KotlinSyntheticClass; public class SamWrapperCodegen extends ParentCodegenAwareImpl { private static final String FUNCTION_FIELD_NAME = "function"; @@ -75,6 +77,8 @@ public class SamWrapperCodegen extends ParentCodegenAwareImpl { ); cv.visitSource(file.getName(), null); + writeKotlinSyntheticClassAnnotation(cv, KotlinSyntheticClass.Kind.SAM_WRAPPER); + // e.g. ASM type for Function2 Type functionAsmType = state.getTypeMapper().mapType(functionType); diff --git a/compiler/tests/org/jetbrains/jet/codegen/KotlinSyntheticClassAnnotationTest.java b/compiler/tests/org/jetbrains/jet/codegen/KotlinSyntheticClassAnnotationTest.java index df7bd04d882..41b7f72256e 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/KotlinSyntheticClassAnnotationTest.java +++ b/compiler/tests/org/jetbrains/jet/codegen/KotlinSyntheticClassAnnotationTest.java @@ -16,20 +16,22 @@ package org.jetbrains.jet.codegen; +import com.google.common.base.Predicate; +import com.google.common.collect.Collections2; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.ConfigurationKind; import org.jetbrains.jet.OutputFile; -import org.jetbrains.jet.OutputFileCollection; import org.jetbrains.jet.lang.resolve.java.AbiVersionUtil; import org.jetbrains.jet.lang.resolve.java.JvmAbi; -import org.jetbrains.jet.lang.resolve.java.JvmClassName; -import org.jetbrains.jet.lang.resolve.java.PackageClassUtils; import org.jetbrains.jet.lang.resolve.name.FqName; import java.lang.annotation.Annotation; +import java.util.Collection; +import java.util.List; import static org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames.ABI_VERSION_FIELD_NAME; import static org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames.KotlinSyntheticClass; +import static org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames.KotlinSyntheticClass.Kind.*; public class KotlinSyntheticClassAnnotationTest extends CodegenTestCase { public static final FqName PACKAGE_NAME = new FqName("test"); @@ -40,36 +42,69 @@ public class KotlinSyntheticClassAnnotationTest extends CodegenTestCase { createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.JDK_ONLY); } - public void testAnnotationIsWrittenOnPackagePart() throws Exception { - loadText("package " + PACKAGE_NAME + "\n\nfun foo() = 42\n"); - String facadeFileName = JvmClassName.byFqNameWithoutInnerClasses(PackageClassUtils.getPackageClassFqName(PACKAGE_NAME)).getInternalName() + ".class"; - - OutputFileCollection outputFiles = generateClassesInFile(); - for (OutputFile outputFile : outputFiles.asList()) { - // The file which is not a facade is a package part - String filePath = outputFile.getRelativePath(); - if (filePath.equals(facadeFileName)) continue; - - String fqName = filePath.substring(0, filePath.length() - ".class".length()).replace('/', '.'); - Class aClass = generateClass(fqName); - - assertAnnotatedWithKind(aClass, "PACKAGE_PART"); - return; - } - - fail("No package part was found: " + outputFiles.asList()); + public void testPackagePart() { + doTest("fun foo() = 42", + "-", + PACKAGE_PART); } - public void testAnnotationIsWrittenOnTraitImpl() throws Exception { - loadText("package " + PACKAGE_NAME + "\n\ntrait A { fun foo() = 42 }\n"); - - Class aClass = generateClass(PACKAGE_NAME + ".A" + JvmAbi.TRAIT_IMPL_SUFFIX); - assertNotNull("TImpl is not generated", aClass); - assertAnnotatedWithKind(aClass, "TRAIT_IMPL"); + public void testTraitImpl() { + doTest("trait A { fun foo() = 42 }", + JvmAbi.TRAIT_IMPL_SUFFIX, + TRAIT_IMPL); } - private void assertAnnotatedWithKind(@NotNull Class aClass, @NotNull String expectedKind) { - Class annotationClass = loadAnnotationClassQuietly(KotlinSyntheticClass.FQ_NAME.asString()); + public void testSamWrapper() { + doTest("val f = {}\nval foo = Thread(f)", + "$sam", + SAM_WRAPPER); + } + + public void testSamLambda() { + doTest("val foo = Thread { }", + "$", + SAM_LAMBDA); + } + + public void testCallableReferenceWrapper() { + doTest("val f = String::get", + "$", + CALLABLE_REFERENCE_WRAPPER); + } + + public void testLocalFunction() { + doTest("fun foo() { fun bar() {} }", + "$", + LOCAL_FUNCTION); + } + + public void testAnonymousFunction() { + doTest("val f = {}", + "$", + ANONYMOUS_FUNCTION); + } + + private void doTest(@NotNull String code, @NotNull final String classNamePart, @NotNull KotlinSyntheticClass.Kind expectedKind) { + loadText("package " + PACKAGE_NAME + "\n\n" + code); + List output = generateClassesInFile().asList(); + Collection files = Collections2.filter(output, new Predicate() { + @Override + public boolean apply(OutputFile file) { + return file.getRelativePath().contains(classNamePart); + } + }); + assertFalse("No files with \"" + classNamePart + "\" in the name are found: " + output, files.isEmpty()); + assertTrue("Exactly one file with \"" + classNamePart + "\" in the name should be found: " + files, files.size() == 1); + + String path = files.iterator().next().getRelativePath(); + String fqName = path.substring(0, path.length() - ".class".length()).replace('/', '.'); + Class aClass = generateClass(fqName); + assertAnnotatedWithKind(aClass, expectedKind); + } + + private void assertAnnotatedWithKind(@NotNull Class aClass, @NotNull KotlinSyntheticClass.Kind expectedKind) { + Class annotationClass = loadAnnotationClassQuietly( + KotlinSyntheticClass.CLASS_NAME.getFqNameForClassNameWithoutDollars().asString()); assertTrue("No KotlinSyntheticClass annotation found", aClass.isAnnotationPresent(annotationClass)); Annotation annotation = aClass.getAnnotation(annotationClass); @@ -80,6 +115,6 @@ public class KotlinSyntheticClassAnnotationTest extends CodegenTestCase { Object actualKind = CodegenTestUtil.getAnnotationAttribute(annotation, KotlinSyntheticClass.KIND_FIELD_NAME.asString()); assertNotNull(actualKind); - assertEquals("KotlinSyntheticClass annotation has the wrong kind", expectedKind, actualKind.toString()); + assertEquals("KotlinSyntheticClass annotation has the wrong kind", expectedKind.toString(), actualKind.toString()); } } diff --git a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/JvmAnnotationNames.java b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/JvmAnnotationNames.java index a3542559f36..d1cc7765484 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/JvmAnnotationNames.java +++ b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/JvmAnnotationNames.java @@ -17,6 +17,7 @@ package org.jetbrains.jet.lang.resolve.java; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.lang.resolve.name.Name; @@ -37,8 +38,7 @@ public final class JvmAnnotationNames { public static final FqName JETBRAINS_READONLY_ANNOTATION = new FqName("org.jetbrains.annotations.ReadOnly"); public static class KotlinSyntheticClass { - public static final FqName FQ_NAME = new FqName("kotlin.jvm.internal.KotlinSyntheticClass"); - public static final String INTERNAL_NAME = JvmClassName.byFqNameWithoutInnerClasses(FQ_NAME).getInternalName(); + public static final JvmClassName CLASS_NAME = JvmClassName.byInternalName("kotlin/jvm/internal/KotlinSyntheticClass"); public static final String KIND_INTERNAL_NAME = "kotlin/jvm/internal/KotlinSyntheticClass$Kind"; public static final Name KIND_FIELD_NAME = Name.identifier("kind"); @@ -49,7 +49,23 @@ public final class JvmAnnotationNames { */ public enum Kind { PACKAGE_PART, - TRAIT_IMPL + TRAIT_IMPL, + SAM_WRAPPER, + SAM_LAMBDA, + CALLABLE_REFERENCE_WRAPPER, + LOCAL_FUNCTION, + ANONYMOUS_FUNCTION, + ; + + @Nullable + public static Kind valueOfOrNull(@NotNull String name) { + try { + return valueOf(name); + } + catch (IllegalArgumentException e) { + return null; + } + } } private KotlinSyntheticClass() { diff --git a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/header/KotlinClassHeader.java b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/header/KotlinClassHeader.java index b40f49ea5ef..b045c42c886 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/header/KotlinClassHeader.java +++ b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/header/KotlinClassHeader.java @@ -19,26 +19,36 @@ package org.jetbrains.jet.lang.resolve.kotlin.header; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import static org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames.KotlinSyntheticClass; + public class KotlinClassHeader { public enum Kind { + INCOMPATIBLE_ABI_VERSION, CLASS, PACKAGE_FACADE, - PACKAGE_PART, - TRAIT_IMPL, - INCOMPATIBLE_ABI_VERSION + SYNTHETIC_CLASS, } private final Kind kind; private final int version; private final String[] data; + private final KotlinSyntheticClass.Kind syntheticClassKind; - public KotlinClassHeader(@NotNull Kind kind, int version, @Nullable String[] annotationData) { + public KotlinClassHeader( + @NotNull Kind kind, + int version, + @Nullable String[] annotationData, + @Nullable KotlinSyntheticClass.Kind syntheticClassKind + ) { assert (annotationData == null) == (kind != Kind.CLASS && kind != Kind.PACKAGE_FACADE) - : "Annotation data should be not null only for CLASS and PACKAGE_FACADE"; + : "Annotation data should be not null only for CLASS and PACKAGE_FACADE (kind=" + kind + ")"; + assert (syntheticClassKind == null) == (kind != Kind.SYNTHETIC_CLASS) + : "Synthetic class kind should be present for SYNTHETIC_CLASS (kind=" + kind + ")"; this.kind = kind; this.version = version; this.data = annotationData; + this.syntheticClassKind = syntheticClassKind; } @NotNull @@ -54,4 +64,9 @@ public class KotlinClassHeader { public String[] getAnnotationData() { return data; } + + @Nullable + public KotlinSyntheticClass.Kind getSyntheticClassKind() { + return syntheticClassKind; + } } diff --git a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/header/ReadKotlinClassHeaderAnnotationVisitor.java b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/header/ReadKotlinClassHeaderAnnotationVisitor.java index 7646cf3b4ca..6d1ff71f11e 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/header/ReadKotlinClassHeaderAnnotationVisitor.java +++ b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/kotlin/header/ReadKotlinClassHeaderAnnotationVisitor.java @@ -33,29 +33,25 @@ import static org.jetbrains.jet.lang.resolve.kotlin.KotlinJvmBinaryClass.Annotat import static org.jetbrains.jet.lang.resolve.kotlin.header.KotlinClassHeader.Kind.*; public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor { - private static final JvmClassName KOTLIN_CLASS_ANNOTATION = JvmClassName.byFqNameWithoutInnerClasses(KOTLIN_CLASS); - private static final JvmClassName KOTLIN_PACKAGE_ANNOTATION = JvmClassName.byFqNameWithoutInnerClasses(KOTLIN_PACKAGE); - private static final JvmClassName KOTLIN_SYNTHETIC_CLASS_ANNOTATION = JvmClassName.byInternalName(KotlinSyntheticClass.INTERNAL_NAME); - private static final Set ALL_SUPPORTED_ANNOTATIONS = new HashSet(); + private static final Map HEADER_KINDS = new HashMap(); static { - ALL_SUPPORTED_ANNOTATIONS.add(KOTLIN_CLASS_ANNOTATION); - ALL_SUPPORTED_ANNOTATIONS.add(KOTLIN_PACKAGE_ANNOTATION); - ALL_SUPPORTED_ANNOTATIONS.add(KOTLIN_SYNTHETIC_CLASS_ANNOTATION); + HEADER_KINDS.put(JvmClassName.byFqNameWithoutInnerClasses(KOTLIN_CLASS), CLASS); + HEADER_KINDS.put(JvmClassName.byFqNameWithoutInnerClasses(KOTLIN_PACKAGE), PACKAGE_FACADE); + HEADER_KINDS.put(KotlinSyntheticClass.CLASS_NAME, SYNTHETIC_CLASS); @SuppressWarnings("deprecation") List incompatible = Arrays.asList(OLD_JET_CLASS_ANNOTATION, OLD_JET_PACKAGE_CLASS_ANNOTATION, OLD_KOTLIN_CLASS, OLD_KOTLIN_PACKAGE, OLD_KOTLIN_PACKAGE_FRAGMENT, OLD_KOTLIN_TRAIT_IMPL); for (FqName fqName : incompatible) { - ALL_SUPPORTED_ANNOTATIONS.add(JvmClassName.byFqNameWithoutInnerClasses(fqName)); + HEADER_KINDS.put(JvmClassName.byFqNameWithoutInnerClasses(fqName), INCOMPATIBLE_ABI_VERSION); } } private int version = AbiVersionUtil.INVALID_VERSION; - @Nullable private String[] annotationData = null; - @Nullable private KotlinClassHeader.Kind headerKind = null; + private KotlinSyntheticClass.Kind syntheticClassKind = null; private ReadKotlinClassHeaderAnnotationVisitor() { } @@ -74,7 +70,7 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor } if (!AbiVersionUtil.isAbiVersionCompatible(version)) { - return new KotlinClassHeader(INCOMPATIBLE_ABI_VERSION, version, null); + return new KotlinClassHeader(INCOMPATIBLE_ABI_VERSION, version, null, null); } if ((headerKind == CLASS || headerKind == PACKAGE_FACADE) && annotationData == null) { @@ -82,29 +78,29 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor // We tell the outside world that there's really no annotation at all return null; } - return new KotlinClassHeader(headerKind, version, annotationData); + + return new KotlinClassHeader(headerKind, version, annotationData, syntheticClassKind); } @Nullable @Override public AnnotationArgumentVisitor visitAnnotation(@NotNull JvmClassName annotation) { - if (!ALL_SUPPORTED_ANNOTATIONS.contains(annotation)) return null; + KotlinClassHeader.Kind newKind = HEADER_KINDS.get(annotation); + if (newKind == null) return null; if (headerKind != null) { // Ignore all Kotlin annotations except the first found return null; } - if (annotation.equals(KOTLIN_CLASS_ANNOTATION) || annotation.equals(KOTLIN_PACKAGE_ANNOTATION)) { - headerKind = annotation.equals(KOTLIN_CLASS_ANNOTATION) ? CLASS : PACKAGE_FACADE; + headerKind = newKind; + + if (newKind == CLASS || newKind == PACKAGE_FACADE) { return kotlinClassOrPackageVisitor(annotation); } - else if (annotation.equals(KOTLIN_SYNTHETIC_CLASS_ANNOTATION)) { + else if (newKind == SYNTHETIC_CLASS) { return syntheticClassAnnotationVisitor(); } - else { - headerKind = INCOMPATIBLE_ABI_VERSION; - } return null; } @@ -181,24 +177,17 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor return new AnnotationArgumentVisitor() { @Override public void visit(@Nullable Name name, @Nullable Object value) { - visitIntValueForSupportedAnnotation(name, value, KOTLIN_SYNTHETIC_CLASS_ANNOTATION); + visitIntValueForSupportedAnnotation(name, value, KotlinSyntheticClass.CLASS_NAME); } @Override public void visitEnum(@NotNull Name name, @NotNull JvmClassName enumClassName, @NotNull Name enumEntryName) { if (enumClassName.getInternalName().equals(KotlinSyntheticClass.KIND_INTERNAL_NAME) && name.equals(KotlinSyntheticClass.KIND_FIELD_NAME)) { - String value = enumEntryName.asString(); // Don't call KotlinSyntheticClass.Kind.valueOf() here, because it will throw an exception if there's no such value, // but we don't want to fail if we're loading the header with an _incompatible_ ABI version - if (value.equals(KotlinSyntheticClass.Kind.PACKAGE_PART.toString())) { - headerKind = PACKAGE_PART; - return; - } - else if (value.equals(KotlinSyntheticClass.Kind.TRAIT_IMPL.toString())) { - headerKind = TRAIT_IMPL; - return; - } + syntheticClassKind = KotlinSyntheticClass.Kind.valueOfOrNull(enumEntryName.asString()); + if (syntheticClassKind != null) return; } if (isAbiVersionCompatible(version)) { throw new IllegalStateException("Unexpected enum entry for synthetic class annotation: " + @@ -209,7 +198,7 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor @Nullable @Override public AnnotationArgumentVisitor visitArray(@NotNull Name name) { - return unexpectedArgument(name, KOTLIN_SYNTHETIC_CLASS_ANNOTATION); + return unexpectedArgument(name, KotlinSyntheticClass.CLASS_NAME); } @Override diff --git a/core/runtime.jvm/src/kotlin/jvm/internal/KotlinSyntheticClass.java b/core/runtime.jvm/src/kotlin/jvm/internal/KotlinSyntheticClass.java index a04b90f60d1..63fb158ed08 100644 --- a/core/runtime.jvm/src/kotlin/jvm/internal/KotlinSyntheticClass.java +++ b/core/runtime.jvm/src/kotlin/jvm/internal/KotlinSyntheticClass.java @@ -27,6 +27,11 @@ public @interface KotlinSyntheticClass { public static enum Kind { PACKAGE_PART, - TRAIT_IMPL + TRAIT_IMPL, + SAM_WRAPPER, + SAM_LAMBDA, + CALLABLE_REFERENCE_WRAPPER, + LOCAL_FUNCTION, + ANONYMOUS_FUNCTION, } } diff --git a/idea/src/org/jetbrains/jet/plugin/libraries/DecompiledUtils.kt b/idea/src/org/jetbrains/jet/plugin/libraries/DecompiledUtils.kt index 8380f6fa673..da627c96963 100644 --- a/idea/src/org/jetbrains/jet/plugin/libraries/DecompiledUtils.kt +++ b/idea/src/org/jetbrains/jet/plugin/libraries/DecompiledUtils.kt @@ -22,6 +22,7 @@ import org.jetbrains.jet.lang.resolve.kotlin.KotlinBinaryClassCache import org.jetbrains.jet.lang.resolve.kotlin.header.KotlinClassHeader import org.jetbrains.jet.lang.resolve.kotlin.header.KotlinClassHeader.Kind import com.intellij.psi.ClassFileViewProvider +import org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames.KotlinSyntheticClass //TODO: this should be done via generic mechanism (special header kind) @@ -47,7 +48,7 @@ public fun isKotlinCompiledFile(file: VirtualFile): Boolean { return false } val header = KotlinBinaryClassCache.getKotlinBinaryClass(file).getClassHeader() - return header != null && header.getKind() != KotlinClassHeader.Kind.TRAIT_IMPL + return header != null && header.getSyntheticClassKind() != KotlinSyntheticClass.Kind.TRAIT_IMPL } public fun isKotlinCompiledFileWithIncompatibleAbiVersion(file: VirtualFile): Boolean { @@ -69,5 +70,5 @@ public fun isKotlinInternalCompiledFile(file: VirtualFile): Boolean { return true } val header = KotlinBinaryClassCache.getKotlinBinaryClass(file).getClassHeader() - return header?.getKind() == KotlinClassHeader.Kind.PACKAGE_PART -} \ No newline at end of file + return header?.getKind() == KotlinClassHeader.Kind.SYNTHETIC_CLASS +}