Split KotlinInfo annotation into two: KotlinClass and KotlinPackage

Two annotations are needed to properly distinguish package classes
This commit is contained in:
Pavel V. Talanov
2013-07-05 20:55:35 +04:00
committed by Alexander Udalov
parent 8a508fe938
commit 977cd7608a
12 changed files with 95 additions and 51 deletions
@@ -24,7 +24,6 @@ import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.jet.lang.resolve.constants.StringValue;
import org.jetbrains.jet.lang.resolve.java.kt.PsiAnnotationWithFlags;
import org.jetbrains.jet.lang.resolve.java.wrapper.PsiClassWrapper;
import org.jetbrains.jet.lang.resolve.java.wrapper.PsiMemberWrapper;
import org.jetbrains.jet.lang.resolve.java.wrapper.PsiMethodWrapper;
import org.jetbrains.jet.lang.resolve.name.FqName;
@@ -46,9 +45,14 @@ public final class DescriptorResolverUtils {
private DescriptorResolverUtils() {
}
//TODO: check that method is used properly
public static boolean isKotlinClass(@NotNull PsiClass psiClass) {
PsiClassWrapper wrapper = new PsiClassWrapper(psiClass);
return wrapper.getJetClass().isDefined() || wrapper.getJetPackageClass().isDefined();
PsiModifierList modifierList = psiClass.getModifierList();
if (modifierList == null) {
return false;
}
PsiAnnotation kotlinClassAnnotation = modifierList.findAnnotation(JvmStdlibNames.KOTLIN_CLASS.getFqName().asString());
return kotlinClassAnnotation != null;
}
@NotNull
@@ -16,7 +16,8 @@
package org.jetbrains.jet.lang.resolve.java;
import jet.KotlinInfo;
import jet.KotlinClass;
import jet.KotlinPackage;
import jet.runtime.typeinfo.JetConstructor;
public class JvmStdlibNames {
@@ -69,7 +70,9 @@ public class JvmStdlibNames {
*/
public static final String JET_CONSTRUCTOR_HIDDEN_FIELD = "hidden";
public static final JvmClassName KOTLIN_INFO_CLASS = JvmClassName.byFqNameWithoutInnerClasses(KotlinInfo.class.getCanonicalName());
public static final JvmClassName KOTLIN_CLASS = JvmClassName.byFqNameWithoutInnerClasses(KotlinClass.class.getCanonicalName());
public static final JvmClassName KOTLIN_PACKAGE = JvmClassName.byFqNameWithoutInnerClasses(KotlinPackage.class.getCanonicalName());
public static final JvmClassName JET_CLASS = JvmClassName.byFqNameWithoutInnerClasses("jet.runtime.typeinfo.JetClass");
@@ -33,10 +33,7 @@ import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
import org.jetbrains.jet.lang.resolve.java.DescriptorResolverUtils;
import org.jetbrains.jet.lang.resolve.java.JvmAbi;
import org.jetbrains.jet.lang.resolve.java.PackageClassUtils;
import org.jetbrains.jet.lang.resolve.java.PsiClassFinder;
import org.jetbrains.jet.lang.resolve.java.*;
import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lang.resolve.name.Name;
import org.jetbrains.jet.utils.ExceptionUtils;
@@ -133,7 +130,9 @@ public class AnnotationDescriptorDeserializer implements AnnotationDeserializer
private static boolean ignoreAnnotation(@NotNull String desc) {
// TODO: JvmAbi.JETBRAINS_NOT_NULL_ANNOTATION ?
return desc.equals(DeserializedDescriptorResolver.KOTLIN_INFO_TYPE) || desc.startsWith("Ljet/runtime/typeinfo/");
return desc.equals(JvmStdlibNames.KOTLIN_CLASS.getDescriptor())
|| desc.equals(JvmStdlibNames.KOTLIN_PACKAGE.getDescriptor())
|| desc.startsWith("Ljet/runtime/typeinfo/");
}
@NotNull
@@ -223,7 +222,8 @@ public class AnnotationDescriptorDeserializer implements AnnotationDeserializer
@NotNull
private Map<MemberSignature, List<AnnotationDescriptor>> loadMemberAnnotationsFromFile(@NotNull VirtualFile file) throws IOException {
final Map<MemberSignature, List<AnnotationDescriptor>> memberAnnotations = new HashMap<MemberSignature, List<AnnotationDescriptor>>();
final Map<MemberSignature, List<AnnotationDescriptor>> memberAnnotations =
new HashMap<MemberSignature, List<AnnotationDescriptor>>();
new ClassReader(file.getInputStream()).accept(new ClassVisitor(Opcodes.ASM4) {
@Override
@@ -291,7 +291,9 @@ public class AnnotationDescriptorDeserializer implements AnnotationDeserializer
else if (syntheticMethodName != null) {
return fromMethodNameAndDesc(syntheticMethodName, JvmAbi.ANNOTATED_PROPERTY_METHOD_SIGNATURE);
}
else return null;
else {
return null;
}
}
@Nullable
@@ -51,7 +51,6 @@ import static org.jetbrains.jet.lang.resolve.java.resolver.DeserializedResolverU
import static org.jetbrains.jet.lang.resolve.java.resolver.DeserializedResolverUtils.kotlinFqNameToJavaFqName;
public final class DeserializedDescriptorResolver {
public static final String KOTLIN_INFO_TYPE = JvmStdlibNames.KOTLIN_INFO_CLASS.getAsmType().toString();
private AnnotationDescriptorDeserializer annotationDeserializer;
@@ -140,8 +139,7 @@ public final class DeserializedDescriptorResolver {
DeclarationDescriptor owner = classId.isTopLevelClass()
? javaNamespaceResolver.resolveNamespace(classId.getPackageFqName(), INCLUDE_KOTLIN)
: javaClassResolver
.resolveClass(kotlinFqNameToJavaFqName(classId.getOuterClassId().asSingleFqName()));
: javaClassResolver.resolveClass(kotlinFqNameToJavaFqName(classId.getOuterClassId().asSingleFqName()));
assert owner != null : "No owner found for " + classId;
return new DeserializedClassDescriptor(classId, storageManager, owner, classData.getNameResolver(),
@@ -204,8 +202,9 @@ public final class DeserializedDescriptorResolver {
private String[] data = null;
@Override
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
if (!desc.equals(KOTLIN_INFO_TYPE)) {
public AnnotationVisitor visitAnnotation(final String desc, boolean visible) {
if (!desc.equals(JvmStdlibNames.KOTLIN_CLASS.getDescriptor()) &&
!desc.equals(JvmStdlibNames.KOTLIN_PACKAGE.getDescriptor())) {
return null;
}
@@ -216,7 +215,7 @@ public final class DeserializedDescriptorResolver {
version = (Integer) value;
}
else if (isAbiVersionCompatible(version)) {
throw new IllegalStateException("Unexpected argument " + name + " for annotation " + KOTLIN_INFO_TYPE);
throw new IllegalStateException("Unexpected argument " + name + " for annotation " + desc);
}
}
@@ -226,7 +225,7 @@ public final class DeserializedDescriptorResolver {
return stringArrayVisitor();
}
else if (isAbiVersionCompatible(version)) {
throw new IllegalStateException("Unexpected array argument " + name + " for annotation " + KOTLIN_INFO_TYPE);
throw new IllegalStateException("Unexpected array argument " + name + " for annotation " + desc);
}
return super.visitArray(name);
@@ -83,7 +83,8 @@ public final class JavaAnnotationResolver {
// Don't process internal jet annotations and jetbrains NotNull annotations
if (qname.startsWith("jet.runtime.typeinfo.")
|| qname.equals(JvmAbi.JETBRAINS_NOT_NULL_ANNOTATION.getFqName().asString())
|| qname.equals(JvmStdlibNames.KOTLIN_INFO_CLASS.getFqName().asString())
|| qname.equals(JvmStdlibNames.KOTLIN_CLASS.getFqName().asString())
|| qname.equals(JvmStdlibNames.KOTLIN_PACKAGE.getFqName().asString())
) {
return null;
}
@@ -166,14 +166,14 @@ public final class JavaNamespaceResolver {
trace.record(JavaBindingContext.JAVA_NAMESPACE_KIND, namespaceDescriptor, JavaNamespaceKind.PROPER);
if (psiClass != null) {
boolean compiledKotlinClass = isCompiledKotlinClass(psiClass);
if (isOldKotlinPackageClass(psiClass) && !compiledKotlinClass) {
// If psiClass has old annotations (@JetPackage) but doesn't have @KotlinInfo, report ABI version error
boolean hasKotlinPackageAnnotation = hasKotlinPackageAnnotation(psiClass);
if (isOldKotlinPackageClass(psiClass) && !hasKotlinPackageAnnotation) {
// If psiClass has old annotations (@JetPackage) but doesn't have @KotlinPackage, report ABI version error
AbiVersionUtil.checkAbiVersion(psiClass, INVALID_VERSION, trace);
}
if (compiledKotlinClass) {
// If psiClass has @KotlinInfo (regardless of whether it has @JetPackage or not), deserialize it to Kotlin descriptor.
// Note that @KotlinInfo may still have an old ABI version, in which case null is returned by createKotlinPackageScope
if (hasKotlinPackageAnnotation) {
// If psiClass has @KotlinPackage (regardless of whether it has @JetPackage or not), deserialize it to Kotlin descriptor.
// Note that @KotlinPackage may still have an old ABI version, in which case null is returned by createKotlinPackageScope
JetScope kotlinPackageScope = deserializedDescriptorResolver.createKotlinPackageScope(psiClass, namespaceDescriptor);
if (kotlinPackageScope != null) return kotlinPackageScope;
}
@@ -205,15 +205,20 @@ public final class JavaNamespaceResolver {
return new PsiClassWrapper(psiClass).getJetPackageClass().isDefined();
}
private static boolean isCompiledKotlinClass(@NotNull PsiClass psiClass) {
private static boolean hasKotlinPackageAnnotation(@NotNull PsiClass psiClass) {
// TODO: merge this method with DescriptorResolverUtils#isKotlinClass
// NOTE: we need to check against ClsClassImpl because it can be a Java source, pretending to be a Kotlin class.
// In that case we can't really read the annotation from psiClass's virtual file
if (psiClass instanceof ClsClassImpl) {
PsiModifierList list = psiClass.getModifierList();
if (list != null) {
return list.findAnnotation(JvmStdlibNames.KOTLIN_INFO_CLASS.getFqName().asString()) != null;
}
if (!(psiClass instanceof ClsClassImpl)) {
return false;
}
return hasAnnotation(psiClass, JvmStdlibNames.KOTLIN_PACKAGE.getFqName());
}
private static boolean hasAnnotation(@NotNull PsiClass psiClass, @NotNull FqName annotationFqName) {
PsiModifierList list = psiClass.getModifierList();
if (list != null) {
return list.findAnnotation(annotationFqName.asString()) != null;
}
return false;
}