Read KotlinInfo annotations for packages

JavaNamespaceDescriptor creates DeserializedPackageMemberScope in case there is *Package class present for a particular package (other cases work as before)
This commit is contained in:
Pavel V. Talanov
2013-07-04 14:14:27 +04:00
committed by Alexander Udalov
parent 77aa190eb1
commit 9a33567287
12 changed files with 170 additions and 59 deletions
@@ -154,6 +154,7 @@ public class InjectorForJavaDescriptorResolver {
deserializedDescriptorResolver.setJavaClassResolver(javaClassResolver);
deserializedDescriptorResolver.setJavaNamespaceResolver(javaNamespaceResolver);
javaNamespaceResolver.setDeserializedDescriptorResolver(deserializedDescriptorResolver);
javaNamespaceResolver.setJavaSemanticServices(javaSemanticServices);
javaNamespaceResolver.setPsiClassFinder(psiClassFinder);
javaNamespaceResolver.setTrace(bindingTrace);
@@ -154,6 +154,7 @@ public class InjectorForJavaSemanticServices {
deserializedDescriptorResolver.setJavaClassResolver(javaClassResolver);
deserializedDescriptorResolver.setJavaNamespaceResolver(javaNamespaceResolver);
javaNamespaceResolver.setDeserializedDescriptorResolver(deserializedDescriptorResolver);
javaNamespaceResolver.setJavaSemanticServices(javaSemanticServices);
javaNamespaceResolver.setPsiClassFinder(psiClassFinder);
javaNamespaceResolver.setTrace(bindingTrace);
@@ -332,6 +332,7 @@ public class InjectorForTopDownAnalyzerForJvm implements InjectorForTopDownAnaly
deserializedDescriptorResolver.setJavaClassResolver(javaClassResolver);
deserializedDescriptorResolver.setJavaNamespaceResolver(javaNamespaceResolver);
javaNamespaceResolver.setDeserializedDescriptorResolver(deserializedDescriptorResolver);
javaNamespaceResolver.setJavaSemanticServices(javaSemanticServices);
javaNamespaceResolver.setPsiClassFinder(psiClassFinder);
javaNamespaceResolver.setTrace(bindingTrace);
@@ -16,7 +16,6 @@
package org.jetbrains.jet.lang.resolve.java.resolver;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiClass;
import org.jetbrains.annotations.NotNull;
@@ -28,9 +27,11 @@ import org.jetbrains.asm4.Opcodes;
import org.jetbrains.jet.descriptors.serialization.*;
import org.jetbrains.jet.descriptors.serialization.descriptors.AnnotationDeserializer;
import org.jetbrains.jet.descriptors.serialization.descriptors.DeserializedClassDescriptor;
import org.jetbrains.jet.descriptors.serialization.descriptors.DeserializedPackageMemberScope;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.descriptors.ClassOrNamespaceDescriptor;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor;
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.jet.lang.resolve.java.JvmAbi;
import org.jetbrains.jet.lang.resolve.java.JvmStdlibNames;
@@ -38,7 +39,9 @@ import org.jetbrains.jet.lang.resolve.lazy.storage.LockBasedStorageManager;
import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe;
import org.jetbrains.jet.lang.resolve.name.Name;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
import org.jetbrains.jet.utils.ExceptionUtils;
import javax.inject.Inject;
import java.io.IOException;
@@ -52,7 +55,6 @@ import static org.jetbrains.jet.lang.resolve.java.DescriptorSearchRule.INCLUDE_K
public final class DeserializedDescriptorResolver {
private static final Logger LOG = Logger.getInstance(DeserializedDescriptorResolver.class);
private static final String KOTLIN_INFO_TYPE = JvmStdlibNames.KOTLIN_INFO_CLASS.getAsmType().toString();
public static final AnnotationDeserializer DUMMY_ANNOTATION_DESERIALIZER = new AnnotationDeserializer() {
@@ -91,7 +93,8 @@ public final class DeserializedDescriptorResolver {
private JavaClassResolver javaClassResolver;
private DescriptorFinder javaDescriptorFinder = new DescriptorFinder() {
@NotNull
private final DescriptorFinder javaDescriptorFinder = new DescriptorFinder() {
@Nullable
@Override
public ClassDescriptor findClass(@NotNull ClassId classId) {
@@ -126,6 +129,24 @@ public final class DeserializedDescriptorResolver {
return deserializeClass(classData, fqName, containingDeclaration);
}
@NotNull
public JetScope createKotlinPackageScope(
@NotNull FqName fqName,
@NotNull PsiClass kotlinPackagePsiClass,
@NotNull NamespaceDescriptor packageDescriptor
) {
VirtualFile virtualFile = kotlinPackagePsiClass.getContainingFile().getVirtualFile();
if (virtualFile == null) {
throw new IllegalStateException("Could not find virtual file for " + fqName.asString());
}
PackageData packageData = readPackageDataFromClassFile(virtualFile);
if (packageData == null) {
throw new IllegalStateException("No KotlinInfo annotation stored for " + fqName.asString());
}
return DeserializedPackageMemberScope.createScopeFromPackageData(packageDescriptor, packageData, javaDescriptorFinder,
DUMMY_ANNOTATION_DESERIALIZER, storageManager);
}
@Nullable
private static VirtualFile getVirtualFile(
@NotNull PsiClass psiClass,
@@ -134,8 +155,7 @@ public final class DeserializedDescriptorResolver {
) {
VirtualFile mostOuterClassVirtualFile = psiClass.getContainingFile().getVirtualFile();
if (mostOuterClassVirtualFile == null) {
LOG.error("No virtual file for " + psiClass.getQualifiedName());
return null;
throw new IllegalStateException("Could not find virtual file for " + classFqName.asString());
}
String fileExtension = mostOuterClassVirtualFile.getExtension();
if (fileExtension == null || !fileExtension.equals("class")) {
@@ -147,8 +167,7 @@ public final class DeserializedDescriptorResolver {
String classNameWithBucks = relativeClassName.asString().replace(".", "$") + ".class";
VirtualFile virtualFile = mostOuterClassVirtualFile.getParent().findChild(classNameWithBucks);
if (virtualFile == null) {
LOG.error("No virtual file for " + psiClass.getQualifiedName());
return null;
throw new IllegalStateException("No virtual file for " + classFqName.asString());
}
return virtualFile;
}
@@ -162,8 +181,9 @@ public final class DeserializedDescriptorResolver {
ClassId classId = ClassId.fromFqNameAndContainingDeclaration(fqName, containingDeclaration);
DeclarationDescriptor owner = classId.isTopLevelClass()
? javaNamespaceResolver.resolveNamespace(classId.getPackageFqName(), INCLUDE_KOTLIN)
: javaClassResolver.resolveClass(kotlinFqNameToJavaFqName(classId.getOuterClassId().asSingleFqName()));
? javaNamespaceResolver.resolveNamespace(classId.getPackageFqName(), INCLUDE_KOTLIN)
: javaClassResolver
.resolveClass(kotlinFqNameToJavaFqName(classId.getOuterClassId().asSingleFqName()));
assert owner != null : "No owner found for " + classId;
return new DeserializedClassDescriptor(classId, storageManager, owner, classData.getNameResolver(),
@@ -172,22 +192,48 @@ public final class DeserializedDescriptorResolver {
@Nullable
private static ClassData readClassDataFromClassFile(@NotNull VirtualFile virtualFile) {
byte[] data = getKotlinInfoDataFromClassFile(virtualFile);
if (data == null) return null;
return ClassData.read(data);
}
@Nullable
private static PackageData readPackageDataFromClassFile(@NotNull VirtualFile virtualFile) {
byte[] data = getKotlinInfoDataFromClassFile(virtualFile);
if (data == null) return null;
return PackageData.read(data);
}
@Nullable
private static byte[] getKotlinInfoDataFromClassFile(@NotNull VirtualFile virtualFile) {
GetKotlinInfoDataVisitor visitor = visitClassFile(virtualFile);
if (visitor == null) {
return null;
}
byte[] data = visitor.getData();
if (data == null) {
return null;
}
return data;
}
@Nullable
private static GetKotlinInfoDataVisitor visitClassFile(@NotNull VirtualFile virtualFile) {
try {
InputStream inputStream = virtualFile.getInputStream();
try {
ClassReader reader = new ClassReader(inputStream);
GetKotlinInfoDataVisitor visitor = new GetKotlinInfoDataVisitor();
reader.accept(visitor, SKIP_CODE | SKIP_FRAMES | SKIP_DEBUG);
return visitor.getClassData();
return visitor;
}
finally {
inputStream.close();
}
}
catch (IOException e) {
LOG.error(e);
throw ExceptionUtils.rethrow(e);
}
return null;
}
private static class GetKotlinInfoDataVisitor extends ClassVisitor {
@@ -210,18 +256,15 @@ public final class DeserializedDescriptorResolver {
data = (byte[]) value;
}
else {
LOG.error("Unexpected property " + name + " for annotation " + KOTLIN_INFO_TYPE);
throw new IllegalStateException("Unexpected property " + name + " for annotation " + KOTLIN_INFO_TYPE);
}
}
};
}
@Nullable
private ClassData getClassData() {
if (data == null) {
return null;
}
return ClassSerializationUtil.readClassDataFrom(data);
public byte[] getData() {
return data;
}
}
@@ -28,19 +28,17 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.ModuleDescriptor;
import org.jetbrains.jet.lang.descriptors.ModuleDescriptorImpl;
import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor;
import org.jetbrains.jet.lang.descriptors.impl.NamespaceDescriptorParent;
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.jet.lang.descriptors.impl.NamespaceDescriptorParent;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.BindingTrace;
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
import org.jetbrains.jet.lang.resolve.java.*;
import org.jetbrains.jet.lang.resolve.java.descriptor.JavaNamespaceDescriptor;
import org.jetbrains.jet.lang.resolve.java.kt.JetPackageClassAnnotation;
import org.jetbrains.jet.lang.resolve.java.provider.MembersCache;
import org.jetbrains.jet.lang.resolve.java.scope.JavaBaseScope;
import org.jetbrains.jet.lang.resolve.java.scope.JavaClassStaticMembersScope;
import org.jetbrains.jet.lang.resolve.java.scope.JavaPackageScopeWithoutMembers;
import org.jetbrains.jet.lang.resolve.java.scope.JavaScopeForKotlinNamespace;
import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
@@ -64,6 +62,8 @@ public final class JavaNamespaceResolver {
private BindingTrace trace;
private JavaSemanticServices javaSemanticServices;
private DeserializedDescriptorResolver deserializedDescriptorResolver;
public JavaNamespaceResolver() {
}
@@ -82,6 +82,11 @@ public final class JavaNamespaceResolver {
this.javaSemanticServices = javaSemanticServices;
}
@Inject
public void setDeserializedDescriptorResolver(DeserializedDescriptorResolver deserializedDescriptorResolver) {
this.deserializedDescriptorResolver = deserializedDescriptorResolver;
}
@Nullable
public NamespaceDescriptor resolveNamespace(@NotNull FqName qualifiedName, @NotNull DescriptorSearchRule searchRule) {
// First, let's check that there is no Kotlin package:
@@ -161,15 +166,12 @@ public final class JavaNamespaceResolver {
if (psiClass == null) {
return new JavaPackageScopeWithoutMembers(
namespaceDescriptor,
javaSemanticServices.getPsiDeclarationProviderFactory().createDeclarationProviderForNamespaceWithoutMembers(psiPackage),
javaSemanticServices.getPsiDeclarationProviderFactory()
.createDeclarationProviderForNamespaceWithoutMembers(psiPackage),
fqName, javaSemanticServices);
}
AbiVersionUtil.checkAbiVersion(psiClass, JetPackageClassAnnotation.get(psiClass), trace);
return new JavaScopeForKotlinNamespace(
namespaceDescriptor,
javaSemanticServices.getPsiDeclarationProviderFactory().createDeclarationForKotlinNamespace(psiPackage, psiClass),
fqName, javaSemanticServices);
return createScopeForKotlinPackageClass(fqName, namespaceDescriptor, psiClass);
}
PsiClass psiClass = psiClassFinder.findPsiClass(fqName, PsiClassFinder.RuntimeClassesHandleMode.IGNORE);
@@ -189,6 +191,16 @@ public final class JavaNamespaceResolver {
fqName, javaSemanticServices);
}
@NotNull
private JetScope createScopeForKotlinPackageClass(
@NotNull FqName fqName,
@NotNull NamespaceDescriptor namespaceDescriptor,
@NotNull PsiClass psiClass
) {
//TODO: check abi version
return deserializedDescriptorResolver.createKotlinPackageScope(fqName, psiClass, namespaceDescriptor);
}
private void cache(@NotNull FqName fqName, @Nullable JetScope packageScope) {
if (packageScope == null) {
unresolvedCache.add(fqName);
@@ -217,7 +229,8 @@ public final class JavaNamespaceResolver {
@Nullable
private PsiClass getPsiClassForJavaPackageScope(@NotNull FqName packageFQN) {
return psiClassFinder.findPsiClass(PackageClassUtils.getPackageClassFqName(packageFQN), PsiClassFinder.RuntimeClassesHandleMode.IGNORE);
return psiClassFinder
.findPsiClass(PackageClassUtils.getPackageClassFqName(packageFQN), PsiClassFinder.RuntimeClassesHandleMode.IGNORE);
}
private static boolean hasStaticMembers(@NotNull PsiClass psiClass) {
@@ -17,9 +17,27 @@
package org.jetbrains.jet.descriptors.serialization;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.utils.ExceptionUtils;
import java.io.ByteArrayInputStream;
import java.io.IOException;
public final class ClassData {
@NotNull
public static ClassData read(@NotNull byte[] bytes) {
try {
ByteArrayInputStream in = new ByteArrayInputStream(bytes);
NameResolver nameResolver = NameSerializationUtil.deserializeNameResolver(in);
ProtoBuf.Class classProto = ProtoBuf.Class.parseFrom(in);
return new ClassData(nameResolver, classProto);
}
catch (IOException e) {
throw ExceptionUtils.rethrow(e);
}
}
public class ClassData {
private final NameResolver nameResolver;
private final ProtoBuf.Class classProto;
public ClassData(@NotNull NameResolver nameResolver, @NotNull ProtoBuf.Class classProto) {
@@ -86,19 +86,6 @@ public class ClassSerializationUtil {
}
}
@NotNull
public static ClassData readClassDataFrom(@NotNull byte[] bytes) {
try {
ByteArrayInputStream in = new ByteArrayInputStream(bytes);
NameResolver nameResolver = NameSerializationUtil.deserializeNameResolver(in);
ProtoBuf.Class classProto = ProtoBuf.Class.parseFrom(in);
return new ClassData(nameResolver, classProto);
}
catch (IOException e) {
throw ExceptionUtils.rethrow(e);
}
}
@NotNull
public static ClassId getClassId(@NotNull ClassDescriptor classDescriptor) {
DeclarationDescriptor containingDeclaration = classDescriptor.getContainingDeclaration();
@@ -24,7 +24,7 @@ import java.io.IOException;
public final class PackageData {
@NotNull
public static PackageData readPackageDataFrom(@NotNull byte[] bytes) {
public static PackageData read(@NotNull byte[] bytes) {
try {
ByteArrayInputStream in = new ByteArrayInputStream(bytes);
NameResolver nameResolver = NameSerializationUtil.deserializeNameResolver(in);
@@ -2,15 +2,10 @@ package org.jetbrains.jet.descriptors.serialization.descriptors;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.descriptors.serialization.ClassId;
import org.jetbrains.jet.descriptors.serialization.DescriptorFinder;
import org.jetbrains.jet.descriptors.serialization.DescriptorDeserializer;
import org.jetbrains.jet.descriptors.serialization.ProtoBuf;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.descriptors.ClassifierDescriptor;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor;
import org.jetbrains.jet.descriptors.serialization.*;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
import org.jetbrains.jet.lang.resolve.lazy.storage.LockBasedStorageManager;
import org.jetbrains.jet.lang.resolve.lazy.storage.StorageManager;
import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe;
@@ -22,7 +17,40 @@ import java.util.List;
public abstract class DeserializedPackageMemberScope extends DeserializedMemberScope {
@NotNull
public static DeserializedPackageMemberScope createScopeFromPackageData(
@NotNull NamespaceDescriptor packageDescriptor,
@NotNull final PackageData packageData,
@NotNull DescriptorFinder descriptorFinder,
@NotNull AnnotationDeserializer deserializer,
@NotNull LockBasedStorageManager storageManager
) {
final NameResolver nameResolver = packageData.getNameResolver();
DescriptorDeserializer descriptorDeserializer = DescriptorDeserializer
.create(storageManager, packageDescriptor, nameResolver, descriptorFinder, deserializer);
List<ProtoBuf.Callable> memberList = packageData.getPackageProto().getMemberList();
return new DeserializedPackageMemberScope(storageManager, packageDescriptor, descriptorDeserializer, memberList, descriptorFinder) {
@Nullable
@Override
protected ReceiverParameterDescriptor getImplicitReceiver() {
return ReceiverParameterDescriptor.NO_RECEIVER_PARAMETER;
}
@NotNull
@Override
protected Collection<Name> getClassNames() {
Collection<Integer> nameIds = packageData.getPackageProto().getClassNameList();
List<Name> result = new ArrayList<Name>(nameIds.size());
for (Integer nameId : nameIds) {
result.add(nameResolver.getName(nameId));
}
return result;
}
};
}
private final DescriptorFinder descriptorFinder;
private final FqName packageFqName;
public DeserializedPackageMemberScope(
@@ -71,10 +99,10 @@ public abstract class DeserializedPackageMemberScope extends DeserializedMemberS
private <T extends Collection<? super ClassDescriptor>> T findClassifiers(T result, boolean object) {
for (Name className : getClassNames()) {
ClassDescriptor classDescriptor = (ClassDescriptor) getClassDescriptor(className);
assert classDescriptor != null : "Class not found: " + className;
ClassDescriptor classDescriptor = findClassDescriptor(className, object);
if (classDescriptor.getKind().isObject() == object) {
if (classDescriptor != null) {
assert classDescriptor.getKind().isObject() == object;
result.add(classDescriptor);
}
}
@@ -52,7 +52,7 @@ public class KotlinInfoForPackageTest extends CodegenTestCase {
assertTrue(aClass.isAnnotationPresent(KotlinInfo.class));
KotlinInfo kotlinInfo = (KotlinInfo) aClass.getAnnotation(KotlinInfo.class);
PackageData data = PackageData.readPackageDataFrom(kotlinInfo.data());
PackageData data = PackageData.read(kotlinInfo.data());
Set<String> classNames = collectClassNames(data);
assertSameElements(Arrays.asList("A", "B", "C"), classNames);
@@ -68,7 +68,7 @@ public class KotlinInfoForClassTest extends CodegenTestCase {
public KotlinInfoBasedDescriptorFinder(@NotNull KotlinInfo kotlinInfo) throws IOException {
super(new LockBasedStorageManager(), AnnotationDeserializer.UNSUPPORTED);
this.classData = ClassSerializationUtil.readClassDataFrom(kotlinInfo.data());
this.classData = ClassData.read(kotlinInfo.data());
this.namespace = JetTestUtils.createTestNamespace(NAMESPACE_NAME.shortName());
}
@@ -21,11 +21,11 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.ConfigurationKind;
import org.jetbrains.jet.analyzer.AnalyzeExhaust;
import org.jetbrains.jet.descriptors.serialization.descriptors.DeserializedClassDescriptor;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor;
import org.jetbrains.jet.descriptors.serialization.descriptors.DeserializedPackageMemberScope;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.test.TestCaseWithTmpdir;
import org.jetbrains.jet.test.util.NamespaceComparator;
@@ -63,6 +63,8 @@ public abstract class AbstractLoadCompiledKotlinTest extends TestCaseWithTmpdir
NamespaceDescriptor namespaceFromClass = LoadDescriptorUtil.loadTestNamespaceAndBindingContextFromJavaRoot(
tmpdir, getTestRootDisposable(), ConfigurationKind.JDK_ONLY).first;
checkUsageOfDeserializedScope(namespaceFromClass);
for (DeclarationDescriptor descriptor : namespaceFromClass.getMemberScope().getAllDescriptors()) {
if (descriptor instanceof ClassDescriptor) {
assert descriptor instanceof DeserializedClassDescriptor : DescriptorUtils.getFQName(descriptor);
@@ -75,4 +77,21 @@ public abstract class AbstractLoadCompiledKotlinTest extends TestCaseWithTmpdir
.checkPropertyAccessors(includeAccessors),
txtFile);
}
private static void checkUsageOfDeserializedScope(@NotNull NamespaceDescriptor namespaceFromClass) {
JetScope scope = namespaceFromClass.getMemberScope();
boolean hasOwnMembers = false;
for (DeclarationDescriptor declarationDescriptor : scope.getAllDescriptors()) {
if (declarationDescriptor instanceof CallableMemberDescriptor) {
hasOwnMembers = true;
}
}
if (hasOwnMembers) {
assert scope instanceof DeserializedPackageMemberScope : "If namespace has members, members should be inside deserialized scope.";
}
else {
//NOTE: should probably change
assert !(scope instanceof DeserializedPackageMemberScope) : "We don't use deserialized scopes for namespaces without members.";
}
}
}