Deprecate and don't write KotlinClass$Kind, to be removed later

This commit is contained in:
Alexander Udalov
2015-10-01 19:12:07 +03:00
parent 056bb3f833
commit 041af28166
17 changed files with 101 additions and 158 deletions
@@ -43,7 +43,6 @@ import org.jetbrains.kotlin.incremental.components.NoLookupLocation;
import org.jetbrains.kotlin.lexer.JetTokens; import org.jetbrains.kotlin.lexer.JetTokens;
import org.jetbrains.kotlin.load.java.JvmAbi; import org.jetbrains.kotlin.load.java.JvmAbi;
import org.jetbrains.kotlin.load.java.JvmAnnotationNames; import org.jetbrains.kotlin.load.java.JvmAnnotationNames;
import org.jetbrains.kotlin.load.java.JvmAnnotationNames.KotlinClass;
import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor; import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor;
import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.name.FqName;
import org.jetbrains.kotlin.name.FqNameUnsafe; import org.jetbrains.kotlin.name.FqNameUnsafe;
@@ -256,17 +255,12 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
protected void generateKotlinAnnotation() { protected void generateKotlinAnnotation() {
if (state.getClassBuilderMode() != ClassBuilderMode.FULL) return; if (state.getClassBuilderMode() != ClassBuilderMode.FULL) return;
KotlinClass.Kind kind; if (!isTopLevelOrInnerClass(descriptor)) {
if (isAnonymousObject(descriptor)) { AnnotationVisitor av = v.getVisitor().visitAnnotation(
kind = KotlinClass.Kind.ANONYMOUS_OBJECT; asmDescByFqNameWithoutInnerClasses(JvmAnnotationNames.KOTLIN_LOCAL_CLASS), true
} );
else if (isTopLevelOrInnerClass(descriptor)) { av.visit(JvmAnnotationNames.VERSION_FIELD_NAME, JvmAbi.VERSION.toArray());
// Default value is Kind.CLASS av.visitEnd();
kind = null;
}
else {
// LOCAL_CLASS is also written to inner classes of local classes
kind = KotlinClass.Kind.LOCAL_CLASS;
} }
DescriptorSerializer serializer = DescriptorSerializer serializer =
@@ -276,13 +270,6 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
AnnotationVisitor av = v.getVisitor().visitAnnotation(asmDescByFqNameWithoutInnerClasses(JvmAnnotationNames.KOTLIN_CLASS), true); AnnotationVisitor av = v.getVisitor().visitAnnotation(asmDescByFqNameWithoutInnerClasses(JvmAnnotationNames.KOTLIN_CLASS), true);
writeAnnotationData(av, serializer, classProto); writeAnnotationData(av, serializer, classProto);
if (kind != null) {
av.visitEnum(
JvmAnnotationNames.KIND_FIELD_NAME,
Type.getObjectType(KotlinClass.KIND_INTERNAL_NAME).getDescriptor(),
kind.toString()
);
}
av.visitEnd(); av.visitEnd();
} }
@@ -270,9 +270,6 @@ public abstract class FileBasedKotlinClass implements KotlinJvmBinaryClass {
if (name.equals(JvmAnnotationNames.KotlinSyntheticClass.KIND_INTERNAL_NAME)) { if (name.equals(JvmAnnotationNames.KotlinSyntheticClass.KIND_INTERNAL_NAME)) {
return JvmAnnotationNames.KotlinSyntheticClass.KIND_CLASS_ID; return JvmAnnotationNames.KotlinSyntheticClass.KIND_CLASS_ID;
} }
else if (name.equals(JvmAnnotationNames.KotlinClass.KIND_INTERNAL_NAME)) {
return JvmAnnotationNames.KotlinClass.KIND_CLASS_ID;
}
List<String> classes = new ArrayList<String>(1); List<String> classes = new ArrayList<String>(1);
boolean local = false; boolean local = false;
@@ -20,7 +20,7 @@
method <init>(p0: int): void method <init>(p0: int): void
} }
@kotlin.jvm.internal.KotlinClass LiteralsKt$foo$3 { @kotlin.jvm.internal.KotlinLocalClass @kotlin.jvm.internal.KotlinClass LiteralsKt$foo$3 {
inner class LiteralsKt$foo$3 inner class LiteralsKt$foo$3
field $kotlinClass: kotlin.reflect.KClass field $kotlinClass: kotlin.reflect.KClass
method <clinit>(): void method <clinit>(): void
@@ -185,7 +185,7 @@ public object InlineTestUtil {
} }
private fun isClassOrPackagePartKind(header: KotlinClassHeader): Boolean { private fun isClassOrPackagePartKind(header: KotlinClassHeader): Boolean {
return header.classKind == JvmAnnotationNames.KotlinClass.Kind.CLASS || header.isInterfaceDefaultImpls return (header.kind == KotlinClassHeader.Kind.CLASS && !header.isLocalClass) || header.isInterfaceDefaultImpls
} }
private fun getClassHeader(file: OutputFile): KotlinClassHeader { private fun getClassHeader(file: OutputFile): KotlinClassHeader {
@@ -19,14 +19,12 @@ package org.jetbrains.kotlin.codegen;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.collect.Collections2; import com.google.common.collect.Collections2;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.backend.common.output.OutputFile; import org.jetbrains.kotlin.backend.common.output.OutputFile;
import org.jetbrains.kotlin.load.java.AbiVersionUtil; import org.jetbrains.kotlin.load.java.AbiVersionUtil;
import org.jetbrains.kotlin.load.java.JvmAbi; import org.jetbrains.kotlin.load.java.JvmAbi;
import org.jetbrains.kotlin.load.java.JvmAnnotationNames.KotlinClass; import org.jetbrains.kotlin.load.java.JvmAnnotationNames;
import org.jetbrains.kotlin.load.java.JvmAnnotationNames.KotlinSyntheticClass; import org.jetbrains.kotlin.load.java.JvmAnnotationNames.KotlinSyntheticClass;
import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.name.FqName;
import org.jetbrains.kotlin.resolve.jvm.JvmClassName;
import org.jetbrains.kotlin.serialization.deserialization.BinaryVersion; import org.jetbrains.kotlin.serialization.deserialization.BinaryVersion;
import org.jetbrains.kotlin.test.ConfigurationKind; import org.jetbrains.kotlin.test.ConfigurationKind;
@@ -34,9 +32,6 @@ import java.lang.annotation.Annotation;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import static org.jetbrains.kotlin.load.java.JvmAnnotationNames.KIND_FIELD_NAME;
import static org.jetbrains.kotlin.load.java.JvmAnnotationNames.KotlinClass.Kind.ANONYMOUS_OBJECT;
import static org.jetbrains.kotlin.load.java.JvmAnnotationNames.KotlinClass.Kind.LOCAL_CLASS;
import static org.jetbrains.kotlin.load.java.JvmAnnotationNames.VERSION_FIELD_NAME; import static org.jetbrains.kotlin.load.java.JvmAnnotationNames.VERSION_FIELD_NAME;
public class KotlinSyntheticClassAnnotationTest extends CodegenTestCase { public class KotlinSyntheticClassAnnotationTest extends CodegenTestCase {
@@ -93,8 +88,7 @@ public class KotlinSyntheticClassAnnotationTest extends CodegenTestCase {
public void testLocalClass() { public void testLocalClass() {
doTestKotlinClass( doTestKotlinClass(
"fun foo() { class Local }", "fun foo() { class Local }",
"Local", "Local"
LOCAL_CLASS
); );
} }
@@ -108,24 +102,21 @@ public class KotlinSyntheticClassAnnotationTest extends CodegenTestCase {
public void testLocalTraitInterface() { public void testLocalTraitInterface() {
doTestKotlinClass( doTestKotlinClass(
"fun foo() { interface Local { fun bar() = 42 } }", "fun foo() { interface Local { fun bar() = 42 } }",
"Local.class", "Local.class"
LOCAL_CLASS
); );
} }
public void testInnerClassOfLocalClass() { public void testInnerClassOfLocalClass() {
doTestKotlinClass( doTestKotlinClass(
"fun foo() { class Local { inner class Inner } }", "fun foo() { class Local { inner class Inner } }",
"Inner", "Inner"
LOCAL_CLASS
); );
} }
public void testAnonymousObject() { public void testAnonymousObject() {
doTestKotlinClass( doTestKotlinClass(
"val o = object {}", "val o = object {}",
"$1", "$1"
ANONYMOUS_OBJECT
); );
} }
@@ -138,22 +129,17 @@ public class KotlinSyntheticClassAnnotationTest extends CodegenTestCase {
} }
private void doTestKotlinSyntheticClass(@NotNull String code, @NotNull String classFilePart) { private void doTestKotlinSyntheticClass(@NotNull String code, @NotNull String classFilePart) {
doTest(code, classFilePart, KotlinSyntheticClass.CLASS_NAME, null); doTest(code, classFilePart, KotlinSyntheticClass.CLASS_NAME.getFqNameForClassNameWithoutDollars());
} }
private void doTestKotlinClass( private void doTestKotlinClass(@NotNull String code, @NotNull String classFilePart) {
@NotNull String code, doTest(code, classFilePart, JvmAnnotationNames.KOTLIN_CLASS, JvmAnnotationNames.KOTLIN_LOCAL_CLASS);
@NotNull String classFilePart,
@NotNull KotlinClass.Kind expectedKind
) {
doTest(code, classFilePart, KotlinClass.CLASS_NAME, expectedKind.toString());
} }
private void doTest( private void doTest(
@NotNull String code, @NotNull String code,
@NotNull final String classFilePart, @NotNull final String classFilePart,
@NotNull JvmClassName annotationName, @NotNull FqName... annotationFqNames
@Nullable String expectedKind
) { ) {
loadText("package " + PACKAGE_NAME + "\n\n" + code); loadText("package " + PACKAGE_NAME + "\n\n" + code);
List<OutputFile> output = generateClassesInFile().asList(); List<OutputFile> output = generateClassesInFile().asList();
@@ -169,14 +155,12 @@ public class KotlinSyntheticClassAnnotationTest extends CodegenTestCase {
String path = files.iterator().next().getRelativePath(); String path = files.iterator().next().getRelativePath();
String fqName = path.substring(0, path.length() - ".class".length()).replace('/', '.'); String fqName = path.substring(0, path.length() - ".class".length()).replace('/', '.');
Class<?> aClass = generateClass(fqName); Class<?> aClass = generateClass(fqName);
assertAnnotatedWithKind(aClass, annotationName.getFqNameForClassNameWithoutDollars().asString(), expectedKind); for (FqName annotationFqName : annotationFqNames) {
assertAnnotatedWith(aClass, annotationFqName.asString());
}
} }
private void assertAnnotatedWithKind( private void assertAnnotatedWith(@NotNull Class<?> aClass, @NotNull String annotationFqName) {
@NotNull Class<?> aClass,
@NotNull String annotationFqName,
@Nullable String expectedKind
) {
Class<? extends Annotation> annotationClass = loadAnnotationClassQuietly(annotationFqName); Class<? extends Annotation> annotationClass = loadAnnotationClassQuietly(annotationFqName);
assertTrue("No annotation " + annotationFqName + " found in " + aClass, aClass.isAnnotationPresent(annotationClass)); assertTrue("No annotation " + annotationFqName + " found in " + aClass, aClass.isAnnotationPresent(annotationClass));
@@ -186,9 +170,5 @@ public class KotlinSyntheticClassAnnotationTest extends CodegenTestCase {
assertNotNull(version); assertNotNull(version);
assertTrue("Annotation " + annotationFqName + " is written with an unsupported format", assertTrue("Annotation " + annotationFqName + " is written with an unsupported format",
AbiVersionUtil.isAbiVersionCompatible(BinaryVersion.create(version))); AbiVersionUtil.isAbiVersionCompatible(BinaryVersion.create(version)));
Object actualKind = CodegenTestUtil.getAnnotationAttribute(annotation, KIND_FIELD_NAME);
assertNotNull(actualKind);
assertEquals("Annotation " + annotationFqName + " has the wrong kind", expectedKind, actualKind.toString());
} }
} }
@@ -150,11 +150,10 @@ public abstract class AbstractJvmRuntimeDescriptorLoaderTest : TestCaseWithTmpdi
val packageView = module.getPackage(LoadDescriptorUtil.TEST_PACKAGE_FQNAME) val packageView = module.getPackage(LoadDescriptorUtil.TEST_PACKAGE_FQNAME)
packageScopes.add(packageView.memberScope) packageScopes.add(packageView.memberScope)
} }
else if (header == null || else if (header == null || (header.kind == KotlinClassHeader.Kind.CLASS && !header.isLocalClass)) {
(header.kind == KotlinClassHeader.Kind.CLASS && header.classKind == JvmAnnotationNames.KotlinClass.Kind.CLASS)) {
// Either a normal Kotlin class or a Java class // Either a normal Kotlin class or a Java class
val classId = klass.classId val classId = klass.classId
if (!classId.isLocal()) { if (!classId.isLocal) {
val classDescriptor = module.findClassAcrossModuleDependencies(classId).sure { "Couldn't resolve class $className" } val classDescriptor = module.findClassAcrossModuleDependencies(classId).sure { "Couldn't resolve class $className" }
if (DescriptorUtils.isTopLevelDeclaration(classDescriptor)) { if (DescriptorUtils.isTopLevelDeclaration(classDescriptor)) {
classes.add(classDescriptor) classes.add(classDescriptor)
@@ -76,17 +76,13 @@ public abstract class AbstractLocalClassProtoTest : TestCaseWithTmpdir() {
) )
} }
@Suppress("UNCHECKED_CAST")
private fun assertHasAnnotationData(clazz: Class<*>) { private fun assertHasAnnotationData(clazz: Class<*>) {
@Suppress("UNCHECKED_CAST") checkNotNull(clazz.getAnnotation(
val annotation = clazz.getAnnotation(
clazz.classLoader.loadClass(JvmAnnotationNames.KOTLIN_CLASS.asString()) as Class<Annotation> clazz.classLoader.loadClass(JvmAnnotationNames.KOTLIN_CLASS.asString()) as Class<Annotation>
) )) { "KotlinClass annotation is not found for class $clazz" }
assert(annotation != null) { "KotlinClass annotation is not found for class $clazz" } checkNotNull(clazz.getAnnotation(
clazz.classLoader.loadClass(JvmAnnotationNames.KOTLIN_LOCAL_CLASS.asString()) as Class<Annotation>
val kindMethod = annotation.annotationType().getDeclaredMethod("kind") )) { "KotlinLocalClass annotation is not found for class $clazz" }
val kind = kindMethod(annotation)
assert(kind.toString() != JvmAnnotationNames.KotlinClass.Kind.CLASS.toString()) {
"'kind' should not be CLASS: $clazz (was $kind)"
}
} }
} }
@@ -28,13 +28,14 @@ import java.util.HashSet;
import java.util.Set; import java.util.Set;
public final class JvmAnnotationNames { public final class JvmAnnotationNames {
public static final FqName KOTLIN_CLASS = KotlinClass.CLASS_NAME.getFqNameForClassNameWithoutDollars(); 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_FILE_FACADE = new FqName("kotlin.jvm.internal.KotlinFileFacade"); public static final FqName KOTLIN_FILE_FACADE = new FqName("kotlin.jvm.internal.KotlinFileFacade");
public static final FqName KOTLIN_MULTIFILE_CLASS = new FqName("kotlin.jvm.internal.KotlinMultifileClass"); public static final FqName KOTLIN_MULTIFILE_CLASS = new FqName("kotlin.jvm.internal.KotlinMultifileClass");
public static final FqName KOTLIN_MULTIFILE_CLASS_PART = new FqName("kotlin.jvm.internal.KotlinMultifileClassPart"); public static final FqName KOTLIN_MULTIFILE_CLASS_PART = new FqName("kotlin.jvm.internal.KotlinMultifileClassPart");
public static final FqName KOTLIN_CALLABLE = new FqName("kotlin.jvm.internal.KotlinCallable"); public static final FqName KOTLIN_CALLABLE = new FqName("kotlin.jvm.internal.KotlinCallable");
public static final FqName KOTLIN_INTERFACE_DEFAULT_IMPLS = new FqName("kotlin.jvm.internal.KotlinInterfaceDefaultImpls"); public static final FqName KOTLIN_INTERFACE_DEFAULT_IMPLS = new FqName("kotlin.jvm.internal.KotlinInterfaceDefaultImpls");
public static final FqName KOTLIN_LOCAL_CLASS = new FqName("kotlin.jvm.internal.KotlinLocalClass");
public static final FqName JAVA_LANG_DEPRECATED = new FqName("java.lang.Deprecated"); public static final FqName JAVA_LANG_DEPRECATED = new FqName("java.lang.Deprecated");
@@ -68,23 +69,6 @@ public final class JvmAnnotationNames {
public static final FqName ENHANCED_NULLABILITY_ANNOTATION = new FqName("kotlin.jvm.internal.EnhancedNullability"); public static final FqName ENHANCED_NULLABILITY_ANNOTATION = new FqName("kotlin.jvm.internal.EnhancedNullability");
public static final FqName ENHANCED_MUTABILITY_ANNOTATION = new FqName("kotlin.jvm.internal.EnhancedMutability"); public static final FqName ENHANCED_MUTABILITY_ANNOTATION = new FqName("kotlin.jvm.internal.EnhancedMutability");
public static class KotlinClass {
public static final JvmClassName CLASS_NAME = JvmClassName.byInternalName("kotlin/jvm/internal/KotlinClass");
public static final ClassId KIND_CLASS_ID =
ClassId.topLevel(CLASS_NAME.getFqNameForClassNameWithoutDollars()).createNestedClassId(Name.identifier("Kind"));
public static final String KIND_INTERNAL_NAME = JvmClassName.byClassId(KIND_CLASS_ID).getInternalName();
/**
* This enum duplicates {@link kotlin.jvm.internal.KotlinClass.Kind}. Both places should be updated simultaneously.
*/
public enum Kind {
CLASS,
LOCAL_CLASS,
ANONYMOUS_OBJECT,
;
}
}
public static class KotlinSyntheticClass { public static class KotlinSyntheticClass {
public static final JvmClassName CLASS_NAME = JvmClassName.byInternalName("kotlin/jvm/internal/KotlinSyntheticClass"); public static final JvmClassName CLASS_NAME = JvmClassName.byInternalName("kotlin/jvm/internal/KotlinSyntheticClass");
public static final ClassId KIND_CLASS_ID = public static final ClassId KIND_CLASS_ID =
@@ -125,6 +109,7 @@ public final class JvmAnnotationNames {
} }
SPECIAL_ANNOTATIONS.add(KotlinSyntheticClass.CLASS_NAME); SPECIAL_ANNOTATIONS.add(KotlinSyntheticClass.CLASS_NAME);
SPECIAL_ANNOTATIONS.add(JvmClassName.byFqNameWithoutInnerClasses(KOTLIN_INTERFACE_DEFAULT_IMPLS)); SPECIAL_ANNOTATIONS.add(JvmClassName.byFqNameWithoutInnerClasses(KOTLIN_INTERFACE_DEFAULT_IMPLS));
SPECIAL_ANNOTATIONS.add(JvmClassName.byFqNameWithoutInnerClasses(KOTLIN_LOCAL_CLASS));
for (FqName fqName : Arrays.asList(JETBRAINS_NOT_NULL_ANNOTATION, JETBRAINS_NULLABLE_ANNOTATION)) { for (FqName fqName : Arrays.asList(JETBRAINS_NOT_NULL_ANNOTATION, JETBRAINS_NULLABLE_ANNOTATION)) {
NULLABILITY_ANNOTATIONS.add(JvmClassName.byFqNameWithoutInnerClasses(fqName)); NULLABILITY_ANNOTATIONS.add(JvmClassName.byFqNameWithoutInnerClasses(fqName));
@@ -17,24 +17,22 @@
package org.jetbrains.kotlin.load.kotlin.header package org.jetbrains.kotlin.load.kotlin.header
import org.jetbrains.kotlin.load.java.AbiVersionUtil import org.jetbrains.kotlin.load.java.AbiVersionUtil
import org.jetbrains.kotlin.load.java.JvmAnnotationNames.KotlinClass
import org.jetbrains.kotlin.load.java.JvmAnnotationNames.KotlinSyntheticClass
import org.jetbrains.kotlin.serialization.deserialization.BinaryVersion import org.jetbrains.kotlin.serialization.deserialization.BinaryVersion
public class KotlinClassHeader( class KotlinClassHeader(
public val kind: KotlinClassHeader.Kind, val kind: KotlinClassHeader.Kind,
public val version: BinaryVersion, val version: BinaryVersion,
public val annotationData: Array<String>?, val annotationData: Array<String>?,
public val strings: Array<String>?, val strings: Array<String>?,
public val classKind: KotlinClass.Kind?, val syntheticClassKind: String?,
public val syntheticClassKind: String?, val filePartClassNames: Array<String>?,
public val filePartClassNames: Array<String>?, val multifileClassName: String?,
public val multifileClassName: String?, val isInterfaceDefaultImpls: Boolean,
public val isInterfaceDefaultImpls: Boolean val isLocalClass: Boolean
) { ) {
public val isCompatibleAbiVersion: Boolean get() = AbiVersionUtil.isAbiVersionCompatible(version) val isCompatibleAbiVersion: Boolean get() = AbiVersionUtil.isAbiVersionCompatible(version)
public enum class Kind { enum class Kind {
CLASS, CLASS,
PACKAGE_FACADE, PACKAGE_FACADE,
FILE_FACADE, FILE_FACADE,
@@ -45,13 +43,13 @@ public class KotlinClassHeader(
override fun toString() = override fun toString() =
"$kind " + "$kind " +
(if (classKind != null) "$classKind " else "") + (if (isLocalClass) "(local) " else "") +
(if (syntheticClassKind != null) "$syntheticClassKind " else "") + (if (syntheticClassKind != null) "$syntheticClassKind " else "") +
"version=$version" "version=$version"
} }
public fun KotlinClassHeader.isCompatibleClassKind(): Boolean = isCompatibleAbiVersion && kind == KotlinClassHeader.Kind.CLASS fun KotlinClassHeader.isCompatibleClassKind(): Boolean = isCompatibleAbiVersion && kind == KotlinClassHeader.Kind.CLASS
public fun KotlinClassHeader.isCompatiblePackageFacadeKind(): Boolean = isCompatibleAbiVersion && kind == KotlinClassHeader.Kind.PACKAGE_FACADE fun KotlinClassHeader.isCompatiblePackageFacadeKind(): Boolean = isCompatibleAbiVersion && kind == KotlinClassHeader.Kind.PACKAGE_FACADE
public fun KotlinClassHeader.isCompatibleFileFacadeKind(): Boolean = isCompatibleAbiVersion && kind == KotlinClassHeader.Kind.FILE_FACADE fun KotlinClassHeader.isCompatibleFileFacadeKind(): Boolean = isCompatibleAbiVersion && kind == KotlinClassHeader.Kind.FILE_FACADE
public fun KotlinClassHeader.isCompatibleMultifileClassKind(): Boolean = isCompatibleAbiVersion && kind == KotlinClassHeader.Kind.MULTIFILE_CLASS fun KotlinClassHeader.isCompatibleMultifileClassKind(): Boolean = isCompatibleAbiVersion && kind == KotlinClassHeader.Kind.MULTIFILE_CLASS
public fun KotlinClassHeader.isCompatibleMultifileClassPartKind(): Boolean = isCompatibleAbiVersion && kind == KotlinClassHeader.Kind.MULTIFILE_CLASS_PART fun KotlinClassHeader.isCompatibleMultifileClassPartKind(): Boolean = isCompatibleAbiVersion && kind == KotlinClassHeader.Kind.MULTIFILE_CLASS_PART
@@ -21,6 +21,7 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.descriptors.SourceElement; import org.jetbrains.kotlin.descriptors.SourceElement;
import org.jetbrains.kotlin.load.java.AbiVersionUtil; import org.jetbrains.kotlin.load.java.AbiVersionUtil;
import org.jetbrains.kotlin.name.ClassId; import org.jetbrains.kotlin.name.ClassId;
import org.jetbrains.kotlin.name.FqName;
import org.jetbrains.kotlin.name.Name; import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.resolve.jvm.JvmClassName; import org.jetbrains.kotlin.resolve.jvm.JvmClassName;
import org.jetbrains.kotlin.serialization.deserialization.BinaryVersion; import org.jetbrains.kotlin.serialization.deserialization.BinaryVersion;
@@ -39,7 +40,7 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor
private static final Map<JvmClassName, KotlinClassHeader.Kind> OLD_DEPRECATED_ANNOTATIONS_KINDS = new HashMap<JvmClassName, KotlinClassHeader.Kind>(); private static final Map<JvmClassName, KotlinClassHeader.Kind> OLD_DEPRECATED_ANNOTATIONS_KINDS = new HashMap<JvmClassName, KotlinClassHeader.Kind>();
static { static {
HEADER_KINDS.put(KotlinClass.CLASS_NAME, 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_FILE_FACADE), FILE_FACADE); HEADER_KINDS.put(JvmClassName.byFqNameWithoutInnerClasses(KOTLIN_FILE_FACADE), FILE_FACADE);
HEADER_KINDS.put(JvmClassName.byFqNameWithoutInnerClasses(KOTLIN_MULTIFILE_CLASS), MULTIFILE_CLASS); HEADER_KINDS.put(JvmClassName.byFqNameWithoutInnerClasses(KOTLIN_MULTIFILE_CLASS), MULTIFILE_CLASS);
@@ -66,9 +67,9 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor
private String[] annotationData = null; private String[] annotationData = null;
private String[] strings = null; private String[] strings = null;
private KotlinClassHeader.Kind headerKind = null; private KotlinClassHeader.Kind headerKind = null;
private KotlinClass.Kind classKind = null;
private String syntheticClassKind = null; private String syntheticClassKind = null;
private boolean isInterfaceDefaultImpls = false; private boolean isInterfaceDefaultImpls = false;
private boolean isLocalClass = false;
@Nullable @Nullable
public KotlinClassHeader createHeader() { public KotlinClassHeader createHeader() {
@@ -76,11 +77,6 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor
return null; return null;
} }
if (headerKind == CLASS && classKind == null) {
// Default class kind is Kind.CLASS
classKind = KotlinClass.Kind.CLASS;
}
if (!AbiVersionUtil.isAbiVersionCompatible(version)) { if (!AbiVersionUtil.isAbiVersionCompatible(version)) {
annotationData = null; annotationData = null;
} }
@@ -91,8 +87,8 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor
} }
return new KotlinClassHeader( return new KotlinClassHeader(
headerKind, version, annotationData, strings, classKind, syntheticClassKind, filePartClassNames, multifileClassName, headerKind, version, annotationData, strings, syntheticClassKind, filePartClassNames, multifileClassName,
isInterfaceDefaultImpls isInterfaceDefaultImpls, isLocalClass
); );
} }
@@ -106,10 +102,15 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor
@Nullable @Nullable
@Override @Override
public AnnotationArgumentVisitor visitAnnotation(@NotNull ClassId classId, @NotNull SourceElement source) { public AnnotationArgumentVisitor visitAnnotation(@NotNull ClassId classId, @NotNull SourceElement source) {
if (KOTLIN_INTERFACE_DEFAULT_IMPLS.equals(classId.asSingleFqName())) { FqName fqName = classId.asSingleFqName();
if (KOTLIN_INTERFACE_DEFAULT_IMPLS.equals(fqName)) {
isInterfaceDefaultImpls = true; isInterfaceDefaultImpls = true;
return null; return null;
} }
else if (KOTLIN_LOCAL_CLASS.equals(fqName)) {
isLocalClass = true;
return null;
}
if (headerKind != null) { if (headerKind != null) {
// Ignore all Kotlin annotations except the first found // Ignore all Kotlin annotations except the first found
@@ -269,14 +270,7 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor
private class ClassHeaderReader extends HeaderAnnotationArgumentVisitor { private class ClassHeaderReader extends HeaderAnnotationArgumentVisitor {
public ClassHeaderReader() { public ClassHeaderReader() {
super(KotlinClass.CLASS_NAME); super(JvmClassName.byFqNameWithoutInnerClasses(KOTLIN_CLASS));
}
@Override
public void visitEnum(@NotNull Name name, @NotNull ClassId enumClassId, @NotNull Name enumEntryName) {
if (KotlinClass.KIND_CLASS_ID.equals(enumClassId) && KIND_FIELD_NAME.equals(name.asString())) {
classKind = valueOfOrNull(KotlinClass.Kind.class, enumEntryName.asString());
}
} }
} }
@@ -316,16 +310,4 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor
} }
} }
} }
// This function is needed here because Enum.valueOf() throws 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
@Nullable
private static <E extends Enum<E>> E valueOfOrNull(@NotNull Class<E> enumClass, @NotNull String entry) {
try {
return Enum.valueOf(enumClass, entry);
}
catch (IllegalArgumentException e) {
return null;
}
}
} }
@@ -29,12 +29,14 @@ public @interface KotlinClass {
int[] version() default {}; int[] version() default {};
Kind kind() default Kind.CLASS;
String[] data(); String[] data();
String[] strings(); String[] strings();
@Deprecated
Kind kind() default Kind.CLASS;
@Deprecated
enum Kind { enum Kind {
CLASS, CLASS,
@@ -0,0 +1,28 @@
/*
* Copyright 2010-2015 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.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface KotlinLocalClass {
int[] version() default {};
}
@@ -21,7 +21,6 @@ import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.ClassFileViewProvider import com.intellij.psi.ClassFileViewProvider
import org.jetbrains.kotlin.idea.caches.JarUserDataManager import org.jetbrains.kotlin.idea.caches.JarUserDataManager
import org.jetbrains.kotlin.idea.decompiler.textBuilder.DirectoryBasedClassFinder import org.jetbrains.kotlin.idea.decompiler.textBuilder.DirectoryBasedClassFinder
import org.jetbrains.kotlin.load.java.JvmAnnotationNames.KotlinClass
import org.jetbrains.kotlin.load.kotlin.KotlinBinaryClassCache import org.jetbrains.kotlin.load.kotlin.KotlinBinaryClassCache
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
@@ -71,9 +70,8 @@ public fun isKotlinInternalCompiledFile(file: VirtualFile): Boolean {
val header = KotlinBinaryClassCache.getKotlinBinaryClass(file)?.classHeader ?: return false val header = KotlinBinaryClassCache.getKotlinBinaryClass(file)?.classHeader ?: return false
return header.kind == KotlinClassHeader.Kind.SYNTHETIC_CLASS || return header.kind == KotlinClassHeader.Kind.SYNTHETIC_CLASS ||
(header.kind == KotlinClassHeader.Kind.CLASS && header.classKind != null && header.classKind != KotlinClass.Kind.CLASS) ||
header.kind == KotlinClassHeader.Kind.MULTIFILE_CLASS_PART || header.kind == KotlinClassHeader.Kind.MULTIFILE_CLASS_PART ||
header.syntheticClassKind == "PACKAGE_PART" header.isLocalClass || header.syntheticClassKind == "PACKAGE_PART"
} }
public fun isKotlinJavaScriptInternalCompiledFile(file: VirtualFile): Boolean = public fun isKotlinJavaScriptInternalCompiledFile(file: VirtualFile): Boolean =
@@ -27,7 +27,6 @@ import org.jetbrains.kotlin.idea.decompiler.isKotlinInternalCompiledFile
import org.jetbrains.kotlin.idea.decompiler.textBuilder.DirectoryBasedClassFinder import org.jetbrains.kotlin.idea.decompiler.textBuilder.DirectoryBasedClassFinder
import org.jetbrains.kotlin.idea.decompiler.textBuilder.DirectoryBasedDataFinder import org.jetbrains.kotlin.idea.decompiler.textBuilder.DirectoryBasedDataFinder
import org.jetbrains.kotlin.idea.decompiler.textBuilder.LoggingErrorReporter import org.jetbrains.kotlin.idea.decompiler.textBuilder.LoggingErrorReporter
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
import org.jetbrains.kotlin.load.kotlin.KotlinBinaryClassCache import org.jetbrains.kotlin.load.kotlin.KotlinBinaryClassCache
import org.jetbrains.kotlin.load.kotlin.header.isCompatibleClassKind import org.jetbrains.kotlin.load.kotlin.header.isCompatibleClassKind
import org.jetbrains.kotlin.load.kotlin.header.isCompatibleFileFacadeKind import org.jetbrains.kotlin.load.kotlin.header.isCompatibleFileFacadeKind
@@ -82,7 +81,7 @@ public open class KotlinClsStubBuilder : ClsStubBuilder() {
createPackageFacadeStub(packageProto, packageFqName, context) createPackageFacadeStub(packageProto, packageFqName, context)
} }
header.isCompatibleClassKind() -> { header.isCompatibleClassKind() -> {
if (header.classKind != JvmAnnotationNames.KotlinClass.Kind.CLASS) return null if (header.isLocalClass) return null
val (nameResolver, classProto) = JvmProtoBufUtil.readClassDataFrom(annotationData, strings) val (nameResolver, classProto) = JvmProtoBufUtil.readClassDataFrom(annotationData, strings)
val context = components.createContext(nameResolver, packageFqName) val context = components.createContext(nameResolver, packageFqName)
createTopLevelClassStub(classId, classProto, context) createTopLevelClassStub(classId, classProto, context)
@@ -20,7 +20,6 @@ import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiManager import com.intellij.psi.PsiManager
import org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToDecompiledLibraryTest import org.jetbrains.kotlin.idea.decompiler.navigation.NavigateToDecompiledLibraryTest
import org.jetbrains.kotlin.idea.test.JetLightCodeInsightFixtureTestCase import org.jetbrains.kotlin.idea.test.JetLightCodeInsightFixtureTestCase
import org.jetbrains.kotlin.load.java.JvmAnnotationNames.KotlinClass
import org.jetbrains.kotlin.load.kotlin.KotlinBinaryClassCache import org.jetbrains.kotlin.load.kotlin.KotlinBinaryClassCache
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
import org.junit.Assert import org.junit.Assert
@@ -34,11 +33,8 @@ public abstract class AbstractInternalCompiledClassesTest : JetLightCodeInsightF
protected fun isSyntheticClass(): VirtualFile.() -> Boolean = protected fun isSyntheticClass(): VirtualFile.() -> Boolean =
isFileWithHeader { it.kind == KotlinClassHeader.Kind.SYNTHETIC_CLASS } isFileWithHeader { it.kind == KotlinClassHeader.Kind.SYNTHETIC_CLASS }
private fun isClassOfKind(kind: KotlinClass.Kind): VirtualFile.() -> Boolean = protected fun doTestNoPsiFilesAreBuiltForLocalClass(): Unit =
isFileWithHeader { it.classKind == kind } doTestNoPsiFilesAreBuiltFor("local", isFileWithHeader { it.isLocalClass })
protected fun doTestNoPsiFilesAreBuiltForLocalClass(kind: KotlinClass.Kind): Unit =
doTestNoPsiFilesAreBuiltFor(kind.name(), isClassOfKind(kind))
protected fun doTestNoPsiFilesAreBuiltForSyntheticClasses(): Unit = protected fun doTestNoPsiFilesAreBuiltForSyntheticClasses(): Unit =
doTestNoPsiFilesAreBuiltFor("synthetic", isSyntheticClass()) doTestNoPsiFilesAreBuiltFor("synthetic", isSyntheticClass())
@@ -20,17 +20,13 @@ import com.intellij.psi.ClassFileViewProvider
import com.intellij.testFramework.LightProjectDescriptor import com.intellij.testFramework.LightProjectDescriptor
import org.jetbrains.kotlin.idea.test.JdkAndMockLibraryProjectDescriptor import org.jetbrains.kotlin.idea.test.JdkAndMockLibraryProjectDescriptor
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase import org.jetbrains.kotlin.idea.test.PluginTestCaseBase
import org.jetbrains.kotlin.load.java.JvmAnnotationNames.KotlinClass.Kind.ANONYMOUS_OBJECT
import org.jetbrains.kotlin.load.java.JvmAnnotationNames.KotlinClass.Kind.LOCAL_CLASS
public class InternalCompiledClassesTest : AbstractInternalCompiledClassesTest() { public class InternalCompiledClassesTest : AbstractInternalCompiledClassesTest() {
private val TEST_DATA_PATH = PluginTestCaseBase.getTestDataPathBase() + "/decompiler/internalClasses" private val TEST_DATA_PATH = PluginTestCaseBase.getTestDataPathBase() + "/decompiler/internalClasses"
fun testSyntheticClassesAreInvisible() = doTestNoPsiFilesAreBuiltForSyntheticClasses() fun testSyntheticClassesAreInvisible() = doTestNoPsiFilesAreBuiltForSyntheticClasses()
fun testLocalClassIsInvisible() = doTestNoPsiFilesAreBuiltForLocalClass(LOCAL_CLASS) fun testLocalClassesAreInvisible() = doTestNoPsiFilesAreBuiltForLocalClass()
fun testAnonymousObjectIsInvisible() = doTestNoPsiFilesAreBuiltForLocalClass(ANONYMOUS_OBJECT)
fun testInnerClassIsInvisible() = doTestNoPsiFilesAreBuiltFor("inner or nested class") { fun testInnerClassIsInvisible() = doTestNoPsiFilesAreBuiltFor("inner or nested class") {
ClassFileViewProvider.isInnerClass(this) ClassFileViewProvider.isInnerClass(this)
@@ -31,7 +31,6 @@ import org.jetbrains.kotlin.jps.build.GeneratedJvmClass
import org.jetbrains.kotlin.jps.build.KotlinBuilder import org.jetbrains.kotlin.jps.build.KotlinBuilder
import org.jetbrains.kotlin.jps.incremental.storage.BasicMap import org.jetbrains.kotlin.jps.incremental.storage.BasicMap
import org.jetbrains.kotlin.jps.incremental.storage.BasicStringMap import org.jetbrains.kotlin.jps.incremental.storage.BasicStringMap
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass
import org.jetbrains.kotlin.load.kotlin.ModuleMapping import org.jetbrains.kotlin.load.kotlin.ModuleMapping
import org.jetbrains.kotlin.load.kotlin.PackageClassUtils import org.jetbrains.kotlin.load.kotlin.PackageClassUtils
@@ -216,10 +215,11 @@ public class IncrementalCacheImpl(
constantsMap.process(kotlinClass) + constantsMap.process(kotlinClass) +
inlineFunctionsMap.process(kotlinClass) inlineFunctionsMap.process(kotlinClass)
} }
header.isCompatibleClassKind() && JvmAnnotationNames.KotlinClass.Kind.CLASS == header.classKind -> header.isCompatibleClassKind() && !header.isLocalClass -> {
protoMap.process(kotlinClass, isPackage = false) + protoMap.process(kotlinClass, isPackage = false) +
constantsMap.process(kotlinClass) + constantsMap.process(kotlinClass) +
inlineFunctionsMap.process(kotlinClass) inlineFunctionsMap.process(kotlinClass)
}
else -> ChangesInfo.NO_CHANGES else -> ChangesInfo.NO_CHANGES
} }