Introduce KotlinSyntheticClass annotation

Will be used instead of KotlinPackagePart, KotlinTraitImpl and other
hypothetical annotations we were planning to write on our synthesized classes
(lambdas, local functions, etc.)
This commit is contained in:
Alexander Udalov
2014-02-28 23:38:19 +04:00
parent 8762a02844
commit cfe3619db7
10 changed files with 52 additions and 62 deletions
@@ -37,7 +37,8 @@ import java.util.Collections;
import java.util.List; import java.util.List;
import static org.jetbrains.asm4.Opcodes.*; import static org.jetbrains.asm4.Opcodes.*;
import static org.jetbrains.jet.codegen.AsmUtil.asmDescByFqNameWithoutInnerClasses; import static org.jetbrains.jet.codegen.AsmUtil.asmTypeByFqNameWithoutInnerClasses;
import static org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames.KOTLIN_SYNTHETIC_CLASS;
public class PackagePartCodegen extends MemberCodegen { public class PackagePartCodegen extends MemberCodegen {
@@ -77,7 +78,7 @@ public class PackagePartCodegen extends MemberCodegen {
); );
v.visitSource(jetFile.getName(), null); v.visitSource(jetFile.getName(), null);
writeKotlinPackagePartAnnotation(); writeKotlinAnnotation();
for (JetDeclaration declaration : jetFile.getDeclarations()) { for (JetDeclaration declaration : jetFile.getDeclarations()) {
if (declaration instanceof JetNamedFunction || declaration instanceof JetProperty) { if (declaration instanceof JetNamedFunction || declaration instanceof JetProperty) {
@@ -90,9 +91,11 @@ public class PackagePartCodegen extends MemberCodegen {
v.done(); v.done();
} }
private void writeKotlinPackagePartAnnotation() { private void writeKotlinAnnotation() {
AnnotationVisitor av = v.newAnnotation(asmDescByFqNameWithoutInnerClasses(JvmAnnotationNames.KOTLIN_PACKAGE_PART), true); Type type = asmTypeByFqNameWithoutInnerClasses(KOTLIN_SYNTHETIC_CLASS);
AnnotationVisitor av = v.newAnnotation(type.getDescriptor(), true);
av.visit(JvmAnnotationNames.ABI_VERSION_FIELD_NAME, JvmAbi.VERSION); av.visit(JvmAnnotationNames.ABI_VERSION_FIELD_NAME, JvmAbi.VERSION);
av.visitEnum("kind", "L" + type.getInternalName() + "$Kind;", "PACKAGE_PART");
av.visitEnd(); av.visitEnd();
} }
@@ -19,6 +19,7 @@ package org.jetbrains.jet.codegen;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.asm4.AnnotationVisitor; import org.jetbrains.asm4.AnnotationVisitor;
import org.jetbrains.asm4.Type;
import org.jetbrains.jet.codegen.context.ClassContext; import org.jetbrains.jet.codegen.context.ClassContext;
import org.jetbrains.jet.codegen.state.GenerationState; import org.jetbrains.jet.codegen.state.GenerationState;
import org.jetbrains.jet.lang.psi.JetClassOrObject; import org.jetbrains.jet.lang.psi.JetClassOrObject;
@@ -26,7 +27,8 @@ import org.jetbrains.jet.lang.resolve.java.JvmAbi;
import org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames; import org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames;
import static org.jetbrains.asm4.Opcodes.*; import static org.jetbrains.asm4.Opcodes.*;
import static org.jetbrains.jet.codegen.AsmUtil.asmDescByFqNameWithoutInnerClasses; import static org.jetbrains.jet.codegen.AsmUtil.asmTypeByFqNameWithoutInnerClasses;
import static org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames.KOTLIN_SYNTHETIC_CLASS;
public class TraitImplBodyCodegen extends ClassBodyCodegen { public class TraitImplBodyCodegen extends ClassBodyCodegen {
@@ -54,9 +56,11 @@ public class TraitImplBodyCodegen extends ClassBodyCodegen {
@Override @Override
protected void generateKotlinAnnotation() { protected void generateKotlinAnnotation() {
AnnotationVisitor av = Type type = asmTypeByFqNameWithoutInnerClasses(KOTLIN_SYNTHETIC_CLASS);
v.getVisitor().visitAnnotation(asmDescByFqNameWithoutInnerClasses(JvmAnnotationNames.KOTLIN_TRAIT_IMPL), true); AnnotationVisitor av = v.getVisitor().visitAnnotation(type.getDescriptor(), true);
if (av == null) return;
av.visit(JvmAnnotationNames.ABI_VERSION_FIELD_NAME, JvmAbi.VERSION); av.visit(JvmAnnotationNames.ABI_VERSION_FIELD_NAME, JvmAbi.VERSION);
av.visitEnum("kind", "L" + type.getInternalName() + "$Kind;", "TRAIT_IMPL");
av.visitEnd(); av.visitEnd();
} }
} }
@@ -20,14 +20,15 @@ import org.jetbrains.jet.ConfigurationKind;
import org.jetbrains.jet.OutputFile; import org.jetbrains.jet.OutputFile;
import org.jetbrains.jet.OutputFileCollection; import org.jetbrains.jet.OutputFileCollection;
import org.jetbrains.jet.lang.resolve.java.AbiVersionUtil; import org.jetbrains.jet.lang.resolve.java.AbiVersionUtil;
import org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames;
import org.jetbrains.jet.lang.resolve.java.JvmClassName; import org.jetbrains.jet.lang.resolve.java.JvmClassName;
import org.jetbrains.jet.lang.resolve.java.PackageClassUtils; import org.jetbrains.jet.lang.resolve.java.PackageClassUtils;
import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.lang.resolve.name.FqName;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
public class KotlinPackagePartAnnotationTest extends CodegenTestCase { import static org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames.KOTLIN_SYNTHETIC_CLASS;
public class KotlinSyntheticClassAnnotationTest extends CodegenTestCase {
public static final FqName PACKAGE_NAME = new FqName("test"); public static final FqName PACKAGE_NAME = new FqName("test");
@Override @Override
@@ -36,35 +37,38 @@ public class KotlinPackagePartAnnotationTest extends CodegenTestCase {
createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.JDK_ONLY); createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.JDK_ONLY);
} }
public void testKotlinPackagePartAnnotationIsWritten() throws Exception { public void testAnnotationIsWrittenOnPackagePart() throws Exception {
loadText("package " + PACKAGE_NAME + "\n\nfun foo() = 42\n"); loadText("package " + PACKAGE_NAME + "\n\nfun foo() = 42\n");
String facadeFileName = JvmClassName.byFqNameWithoutInnerClasses(PackageClassUtils.getPackageClassFqName(PACKAGE_NAME)).getInternalName() + ".class"; String facadeFileName = JvmClassName.byFqNameWithoutInnerClasses(PackageClassUtils.getPackageClassFqName(PACKAGE_NAME)).getInternalName() + ".class";
OutputFileCollection outputFiles = generateClassesInFile(); OutputFileCollection outputFiles = generateClassesInFile();
for (OutputFile outputFile : outputFiles.asList()) { for (OutputFile outputFile : outputFiles.asList()) {
// The file which is not a facade is a package part
String filePath = outputFile.getRelativePath(); String filePath = outputFile.getRelativePath();
if (filePath.equals(facadeFileName)) continue;
if (!filePath.equals(facadeFileName)) { String fqName = filePath.substring(0, filePath.length() - ".class".length()).replace('/', '.');
// The file which is not a facade is a package part Class<?> aClass = generateClass(fqName);
String fqName = filePath.substring(0, filePath.length() - ".class".length()).replace('/', '.');
Class<?> aClass = generateClass(fqName);
Class<? extends Annotation> annotationClass = loadAnnotationClassQuietly(JvmAnnotationNames.KOTLIN_PACKAGE_PART.asString()); Class<? extends Annotation> annotationClass = loadAnnotationClassQuietly(KOTLIN_SYNTHETIC_CLASS.asString());
assertTrue("No KotlinSyntheticClass annotation found on a package part", aClass.isAnnotationPresent(annotationClass));
assertTrue("No KotlinPackagePart annotation on a package part", Annotation annotation = aClass.getAnnotation(annotationClass);
aClass.isAnnotationPresent(annotationClass));
Annotation kotlinPackagePart = aClass.getAnnotation(annotationClass); Integer version = (Integer) CodegenTestUtil.getAnnotationAttribute(annotation, "abiVersion");
assertNotNull(version);
assertTrue("KotlinSyntheticClass annotation is written with an unsupported format",
AbiVersionUtil.isAbiVersionCompatible(version));
Integer version = (Integer) CodegenTestUtil.getAnnotationAttribute(kotlinPackagePart, "abiVersion"); Object kind = CodegenTestUtil.getAnnotationAttribute(annotation, "kind");
assertNotNull(version); assertNotNull(kind);
assertTrue("KotlinPackagePart annotation is written with an unsupported format", assertEquals("KotlinSyntheticClass annotation has the wrong kind", "PACKAGE_PART", kind.toString());
AbiVersionUtil.isAbiVersionCompatible(version));
return; return;
}
} }
fail("No package part was found: " + outputFiles.asList()); fail("No package part was found: " + outputFiles.asList());
} }
// TODO: test that annotation is written on TImpl
} }
@@ -23,8 +23,7 @@ import org.jetbrains.jet.lang.resolve.name.Name;
public final class JvmAnnotationNames { public final class JvmAnnotationNames {
public static final FqName KOTLIN_CLASS = new FqName("kotlin.jvm.internal.KotlinClass"); public static final FqName KOTLIN_CLASS = new FqName("kotlin.jvm.internal.KotlinClass");
public static final FqName KOTLIN_PACKAGE = new FqName("kotlin.jvm.internal.KotlinPackage"); public static final FqName KOTLIN_PACKAGE = new FqName("kotlin.jvm.internal.KotlinPackage");
public static final FqName KOTLIN_PACKAGE_PART = new FqName("kotlin.jvm.internal.KotlinPackagePart"); public static final FqName KOTLIN_SYNTHETIC_CLASS = new FqName("kotlin.jvm.internal.KotlinSyntheticClass");
public static final FqName KOTLIN_TRAIT_IMPL = new FqName("kotlin.jvm.internal.KotlinTraitImpl");
public static final FqName KOTLIN_SIGNATURE = new FqName("kotlin.jvm.KotlinSignature"); public static final FqName KOTLIN_SIGNATURE = new FqName("kotlin.jvm.KotlinSignature");
public static final FqName OLD_KOTLIN_SIGNATURE = new FqName("jet.runtime.typeinfo.KotlinSignature"); public static final FqName OLD_KOTLIN_SIGNATURE = new FqName("jet.runtime.typeinfo.KotlinSignature");
@@ -44,7 +44,7 @@ public final class DescriptorResolverUtils {
public static boolean isCompiledKotlinPackageClass(@NotNull JavaClass javaClass) { public static boolean isCompiledKotlinPackageClass(@NotNull JavaClass javaClass) {
if (javaClass.getOriginKind() == JavaClass.OriginKind.COMPILED) { if (javaClass.getOriginKind() == JavaClass.OriginKind.COMPILED) {
return javaClass.findAnnotation(JvmAnnotationNames.KOTLIN_PACKAGE) != null return javaClass.findAnnotation(JvmAnnotationNames.KOTLIN_PACKAGE) != null
|| javaClass.findAnnotation(JvmAnnotationNames.KOTLIN_PACKAGE_PART) != null; || javaClass.findAnnotation(JvmAnnotationNames.KOTLIN_SYNTHETIC_CLASS) != null;
} }
return false; return false;
} }
@@ -24,8 +24,7 @@ public class KotlinClassHeader {
public enum Kind { public enum Kind {
CLASS, CLASS,
PACKAGE_FACADE, PACKAGE_FACADE,
PACKAGE_PART, SYNTHETIC_CLASS,
TRAIT_IMPL,
INCOMPATIBLE_ABI_VERSION INCOMPATIBLE_ABI_VERSION
} }
@@ -39,8 +39,7 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor
static { static {
HEADER_KINDS.put(JvmClassName.byFqNameWithoutInnerClasses(KOTLIN_CLASS), CLASS); HEADER_KINDS.put(JvmClassName.byFqNameWithoutInnerClasses(KOTLIN_CLASS), CLASS);
HEADER_KINDS.put(JvmClassName.byFqNameWithoutInnerClasses(KOTLIN_PACKAGE), PACKAGE_FACADE); HEADER_KINDS.put(JvmClassName.byFqNameWithoutInnerClasses(KOTLIN_PACKAGE), PACKAGE_FACADE);
HEADER_KINDS.put(JvmClassName.byFqNameWithoutInnerClasses(KOTLIN_PACKAGE_PART), PACKAGE_PART); HEADER_KINDS.put(JvmClassName.byFqNameWithoutInnerClasses(KOTLIN_SYNTHETIC_CLASS), SYNTHETIC_CLASS);
HEADER_KINDS.put(JvmClassName.byFqNameWithoutInnerClasses(KOTLIN_TRAIT_IMPL), TRAIT_IMPL);
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
List<FqName> incompatible = Arrays.asList(OLD_JET_CLASS_ANNOTATION, OLD_JET_PACKAGE_CLASS_ANNOTATION, OLD_KOTLIN_CLASS, List<FqName> incompatible = Arrays.asList(OLD_JET_CLASS_ANNOTATION, OLD_JET_PACKAGE_CLASS_ANNOTATION, OLD_KOTLIN_CLASS,
@@ -100,8 +99,8 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor
if (newKind == CLASS || newKind == PACKAGE_FACADE) { if (newKind == CLASS || newKind == PACKAGE_FACADE) {
return kotlinClassOrPackageVisitor(annotationClassName); return kotlinClassOrPackageVisitor(annotationClassName);
} }
else if (newKind == PACKAGE_PART || newKind == TRAIT_IMPL) { else if (newKind == SYNTHETIC_CLASS) {
return annotationWithAbiVersionVisitor(annotationClassName); return syntheticClassAnnotationVisitor(annotationClassName);
} }
return null; return null;
@@ -175,7 +174,7 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor
} }
@NotNull @NotNull
private AnnotationArgumentVisitor annotationWithAbiVersionVisitor(@NotNull final JvmClassName annotationClassName) { private AnnotationArgumentVisitor syntheticClassAnnotationVisitor(@NotNull final JvmClassName annotationClassName) {
return new AnnotationArgumentVisitor() { return new AnnotationArgumentVisitor() {
@Override @Override
public void visit(@Nullable Name name, @Nullable Object value) { public void visit(@Nullable Name name, @Nullable Object value) {
@@ -184,7 +183,7 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor
@Override @Override
public void visitEnum(@NotNull Name name, @NotNull JvmClassName enumClassName, @NotNull Name enumEntryName) { public void visitEnum(@NotNull Name name, @NotNull JvmClassName enumClassName, @NotNull Name enumEntryName) {
unexpectedArgument(name, annotationClassName); // TODO: save kind to somewhere
} }
@Nullable @Nullable
@@ -20,6 +20,13 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
public @interface KotlinPackagePart { public @interface KotlinSyntheticClass {
int abiVersion(); int abiVersion();
Kind kind();
public static enum Kind {
PACKAGE_PART,
TRAIT_IMPL
}
} }
@@ -1,25 +0,0 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package kotlin.jvm.internal;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface KotlinTraitImpl {
int abiVersion();
}
@@ -46,7 +46,7 @@ public class EmptyPackageFragmentClsStubBuilderFactory extends ClsStubBuilderFac
if (file.getName().contains(PackageClassUtils.PACKAGE_CLASS_NAME_SUFFIX + "-") && if (file.getName().contains(PackageClassUtils.PACKAGE_CLASS_NAME_SUFFIX + "-") &&
StdFileTypes.CLASS.getDefaultExtension().equals(file.getExtension())) { StdFileTypes.CLASS.getDefaultExtension().equals(file.getExtension())) {
KotlinClassHeader header = new VirtualFileKotlinClass(LockBasedStorageManager.NO_LOCKS, file).getClassHeader(); KotlinClassHeader header = new VirtualFileKotlinClass(LockBasedStorageManager.NO_LOCKS, file).getClassHeader();
return header != null && header.getKind() == KotlinClassHeader.Kind.PACKAGE_PART; return header != null && header.getKind() == KotlinClassHeader.Kind.SYNTHETIC_CLASS;
} }
return false; return false;
} }