Make an abstraction over VirtualFileFinder

Java descriptor loader now can work with KotlinClassFinder, which finds
abstract KotlinJvmBinaryClass'es: they are based on VirtualFile in the
compiler/IDE and will be based on j.l.Class in the reflection
This commit is contained in:
Alexander Udalov
2013-09-20 21:21:16 +04:00
parent c5bed7a246
commit 7eff1292f0
12 changed files with 218 additions and 67 deletions
@@ -18,7 +18,6 @@ package org.jetbrains.jet.lang.resolve.java.resolver;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.*;
@@ -34,7 +33,8 @@ import org.jetbrains.jet.lang.resolve.java.scope.JavaClassNonStaticMembersScope;
import org.jetbrains.jet.lang.resolve.java.structure.JavaClass;
import org.jetbrains.jet.lang.resolve.java.structure.JavaMethod;
import org.jetbrains.jet.lang.resolve.kotlin.DeserializedDescriptorResolver;
import org.jetbrains.jet.lang.resolve.kotlin.VirtualFileFinder;
import org.jetbrains.jet.lang.resolve.kotlin.KotlinClassFinder;
import org.jetbrains.jet.lang.resolve.kotlin.KotlinJvmBinaryClass;
import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe;
import org.jetbrains.jet.lang.resolve.name.Name;
@@ -71,16 +71,11 @@ public final class JavaClassResolver {
private JavaSupertypeResolver supertypesResolver;
private JavaFunctionResolver functionResolver;
private DeserializedDescriptorResolver deserializedDescriptorResolver;
private VirtualFileFinder virtualFileFinder;
private KotlinClassFinder kotlinClassFinder;
public JavaClassResolver() {
}
@Inject
public void setVirtualFileFinder(VirtualFileFinder virtualFileFinder) {
this.virtualFileFinder = virtualFileFinder;
}
@Inject
public void setCache(JavaResolverCache cache) {
this.cache = cache;
@@ -126,6 +121,11 @@ public final class JavaClassResolver {
this.functionResolver = functionResolver;
}
@Inject
public void setKotlinClassFinder(KotlinClassFinder kotlinClassFinder) {
this.kotlinClassFinder = kotlinClassFinder;
}
@Nullable
public ClassDescriptor resolveClass(@NotNull FqName qualifiedName, @NotNull DescriptorSearchRule searchRule) {
PostponedTasks postponedTasks = new PostponedTasks();
@@ -189,9 +189,9 @@ public final class JavaClassResolver {
private ClassDescriptor doResolveClass(@NotNull FqName qualifiedName, @NotNull PostponedTasks tasks) {
//TODO: correct scope
VirtualFile file = virtualFileFinder.find(qualifiedName);
if (file != null) {
ClassDescriptor deserializedDescriptor = deserializedDescriptorResolver.resolveClass(file);
KotlinJvmBinaryClass kotlinClass = kotlinClassFinder.find(qualifiedName);
if (kotlinClass != null) {
ClassDescriptor deserializedDescriptor = deserializedDescriptorResolver.resolveClass(kotlinClass);
if (deserializedDescriptor != null) {
cache(javaClassToKotlinFqName(qualifiedName), deserializedDescriptor);
return deserializedDescriptor;
@@ -16,7 +16,6 @@
package org.jetbrains.jet.lang.resolve.java.resolver;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.ModuleDescriptor;
@@ -36,7 +35,8 @@ import org.jetbrains.jet.lang.resolve.java.structure.JavaField;
import org.jetbrains.jet.lang.resolve.java.structure.JavaMethod;
import org.jetbrains.jet.lang.resolve.java.structure.JavaPackage;
import org.jetbrains.jet.lang.resolve.kotlin.DeserializedDescriptorResolver;
import org.jetbrains.jet.lang.resolve.kotlin.VirtualFileFinder;
import org.jetbrains.jet.lang.resolve.kotlin.KotlinClassFinder;
import org.jetbrains.jet.lang.resolve.kotlin.KotlinJvmBinaryClass;
import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lang.resolve.name.Name;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
@@ -62,11 +62,11 @@ public final class JavaNamespaceResolver {
private JavaMemberResolver memberResolver;
private DeserializedDescriptorResolver deserializedDescriptorResolver;
private VirtualFileFinder virtualFileFinder;
private KotlinClassFinder kotlinClassFinder;
@Inject
public void setVirtualFileFinder(VirtualFileFinder virtualFileFinder) {
this.virtualFileFinder = virtualFileFinder;
public void setKotlinClassFinder(KotlinClassFinder kotlinClassFinder) {
this.kotlinClassFinder = kotlinClassFinder;
}
@Inject
@@ -153,12 +153,12 @@ public final class JavaNamespaceResolver {
JavaPackage javaPackage = javaClassFinder.findPackage(fqName);
if (javaPackage != null) {
FqName packageClassFqName = PackageClassUtils.getPackageClassFqName(fqName);
VirtualFile virtualFile = virtualFileFinder.find(packageClassFqName);
KotlinJvmBinaryClass kotlinClass = kotlinClassFinder.find(packageClassFqName);
cache.recordProperNamespace(namespaceDescriptor);
if (virtualFile != null) {
JetScope kotlinPackageScope = deserializedDescriptorResolver.createKotlinPackageScope(namespaceDescriptor, virtualFile);
if (kotlinClass != null) {
JetScope kotlinPackageScope = deserializedDescriptorResolver.createKotlinPackageScope(namespaceDescriptor, kotlinClass);
if (kotlinPackageScope != null) {
return kotlinPackageScope;
}
@@ -17,7 +17,6 @@
package org.jetbrains.jet.lang.resolve.kotlin;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.asm4.*;
@@ -57,64 +56,63 @@ public class AnnotationDescriptorDeserializer implements AnnotationDeserializer
private static final Logger LOG = Logger.getInstance(AnnotationDescriptorDeserializer.class);
private JavaClassResolver javaClassResolver;
private VirtualFileFinder virtualFileFinder;
private KotlinClassFinder kotlinClassFinder;
// TODO: a single instance of StorageManager for all computations in resolve-java
private final LockBasedStorageManager storageManager = new LockBasedStorageManager();
private final MemoizedFunctionToNotNull<VirtualFile, Map<MemberSignature, List<AnnotationDescriptor>>> memberAnnotations =
private final MemoizedFunctionToNotNull<KotlinJvmBinaryClass, Map<MemberSignature, List<AnnotationDescriptor>>> memberAnnotations =
storageManager.createMemoizedFunction(
new MemoizedFunctionToNotNull<VirtualFile, Map<MemberSignature, List<AnnotationDescriptor>>>() {
new MemoizedFunctionToNotNull<KotlinJvmBinaryClass, Map<MemberSignature, List<AnnotationDescriptor>>>() {
@NotNull
@Override
public Map<MemberSignature, List<AnnotationDescriptor>> fun(@NotNull VirtualFile file) {
public Map<MemberSignature, List<AnnotationDescriptor>> fun(@NotNull KotlinJvmBinaryClass kotlinClass) {
try {
return loadMemberAnnotationsFromFile(file);
return loadMemberAnnotationsFromClass(kotlinClass);
}
catch (IOException e) {
LOG.error("Error loading member annotations from file: " + file, e);
LOG.error("Error loading member annotations from Kotlin class: " + kotlinClass, e);
return Collections.emptyMap();
}
}
}, StorageManager.ReferenceKind.STRONG);
@Inject
public void setVirtualFileFinder(VirtualFileFinder virtualFileFinder) {
this.virtualFileFinder = virtualFileFinder;
public void setJavaClassResolver(JavaClassResolver javaClassResolver) {
this.javaClassResolver = javaClassResolver;
}
@Inject
public void setJavaClassResolver(JavaClassResolver javaClassResolver) {
this.javaClassResolver = javaClassResolver;
public void setKotlinClassFinder(KotlinClassFinder kotlinClassFinder) {
this.kotlinClassFinder = kotlinClassFinder;
}
@NotNull
@Override
public List<AnnotationDescriptor> loadClassAnnotations(@NotNull ClassDescriptor descriptor, @NotNull ProtoBuf.Class classProto) {
VirtualFile virtualFile = findVirtualFileByDescriptor(descriptor);
if (virtualFile == null) {
// This means that the resource we're constructing the descriptor from is no longer present: VirtualFileFinder had found the
// file earlier, but it can't now
LOG.error("Virtual file for loading class annotations is not found: " + descriptor);
KotlinJvmBinaryClass kotlinClass = findKotlinClassByDescriptor(descriptor);
if (kotlinClass == null) {
// This means that the resource we're constructing the descriptor from is no longer present: KotlinClassFinder had found the
// class earlier, but it can't now
LOG.error("Kotlin class for loading class annotations is not found: " + descriptor);
return Collections.emptyList();
}
try {
return loadClassAnnotationsFromFile(virtualFile);
return loadClassAnnotationsFromClass(kotlinClass);
}
catch (IOException e) {
LOG.error("Error loading member annotations from file: " + virtualFile, e);
LOG.error("Error loading member annotations from Kotlin class: " + kotlinClass, e);
return Collections.emptyList();
}
}
@Nullable
private VirtualFile findVirtualFileByDescriptor(@NotNull ClassOrNamespaceDescriptor descriptor) {
private KotlinJvmBinaryClass findKotlinClassByDescriptor(@NotNull ClassOrNamespaceDescriptor descriptor) {
if (descriptor instanceof ClassDescriptor) {
return virtualFileFinder.find(kotlinFqNameToJavaFqName(naiveKotlinFqName((ClassDescriptor) descriptor)));
return kotlinClassFinder.find(kotlinFqNameToJavaFqName(naiveKotlinFqName((ClassDescriptor) descriptor)));
}
else if (descriptor instanceof NamespaceDescriptor) {
return virtualFileFinder.find(PackageClassUtils.getPackageClassFqName(DescriptorUtils.getFQName(descriptor).toSafe()));
return kotlinClassFinder.find(PackageClassUtils.getPackageClassFqName(DescriptorUtils.getFQName(descriptor).toSafe()));
}
else {
throw new IllegalStateException("Unrecognized descriptor: " + descriptor);
@@ -122,10 +120,10 @@ public class AnnotationDescriptorDeserializer implements AnnotationDeserializer
}
@NotNull
private List<AnnotationDescriptor> loadClassAnnotationsFromFile(@NotNull VirtualFile virtualFile) throws IOException {
private List<AnnotationDescriptor> loadClassAnnotationsFromClass(@NotNull KotlinJvmBinaryClass kotlinClass) throws IOException {
final List<AnnotationDescriptor> result = new ArrayList<AnnotationDescriptor>();
new ClassReader(virtualFile.contentsToByteArray()).accept(new ClassVisitor(Opcodes.ASM4) {
new ClassReader(kotlinClass.getFile().contentsToByteArray()).accept(new ClassVisitor(Opcodes.ASM4) {
@Override
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
return resolveAnnotation(desc, result);
@@ -222,17 +220,17 @@ public class AnnotationDescriptorDeserializer implements AnnotationDeserializer
MemberSignature signature = getCallableSignature(proto, nameResolver, kind);
if (signature == null) return Collections.emptyList();
VirtualFile file = getVirtualFileWithMemberAnnotations(container, proto, nameResolver);
if (file == null) {
LOG.error("Virtual file for loading member annotations is not found: " + container);
KotlinJvmBinaryClass kotlinClass = findClassWithMemberAnnotations(container, proto, nameResolver);
if (kotlinClass == null) {
LOG.error("Kotlin class for loading member annotations is not found: " + container);
}
List<AnnotationDescriptor> annotations = memberAnnotations.fun(file).get(signature);
List<AnnotationDescriptor> annotations = memberAnnotations.fun(kotlinClass).get(signature);
return annotations == null ? Collections.<AnnotationDescriptor>emptyList() : annotations;
}
@Nullable
private VirtualFile getVirtualFileWithMemberAnnotations(
private KotlinJvmBinaryClass findClassWithMemberAnnotations(
@NotNull ClassOrNamespaceDescriptor container,
@NotNull ProtoBuf.Callable proto,
@NotNull NameResolver nameResolver
@@ -240,18 +238,18 @@ public class AnnotationDescriptorDeserializer implements AnnotationDeserializer
if (container instanceof NamespaceDescriptor) {
Name name = loadSrcClassName(proto, nameResolver);
if (name != null) {
return virtualFileFinder.find(getSrcClassFqName((NamespaceDescriptor) container, name));
return kotlinClassFinder.find(getSrcClassFqName((NamespaceDescriptor) container, name));
}
return null;
}
else if (container instanceof ClassDescriptor && ((ClassDescriptor) container).getKind() == ClassKind.CLASS_OBJECT) {
// Backing fields of properties of a class object are generated in the outer class
if (isStaticFieldInOuter(proto)) {
return findVirtualFileByDescriptor((ClassOrNamespaceDescriptor) container.getContainingDeclaration());
return findKotlinClassByDescriptor((ClassOrNamespaceDescriptor) container.getContainingDeclaration());
}
}
return findVirtualFileByDescriptor(container);
return findKotlinClassByDescriptor(container);
}
@NotNull
@@ -316,11 +314,12 @@ public class AnnotationDescriptorDeserializer implements AnnotationDeserializer
}
@NotNull
private Map<MemberSignature, List<AnnotationDescriptor>> loadMemberAnnotationsFromFile(@NotNull VirtualFile file) throws IOException {
private Map<MemberSignature, List<AnnotationDescriptor>> loadMemberAnnotationsFromClass(@NotNull KotlinJvmBinaryClass kotlinClass)
throws IOException {
final Map<MemberSignature, List<AnnotationDescriptor>> memberAnnotations =
new HashMap<MemberSignature, List<AnnotationDescriptor>>();
new ClassReader(file.contentsToByteArray()).accept(new ClassVisitor(Opcodes.ASM4) {
new ClassReader(kotlinClass.getFile().contentsToByteArray()).accept(new ClassVisitor(Opcodes.ASM4) {
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
final MemberSignature methodSignature = MemberSignature.fromMethodNameAndDesc(name, desc);
@@ -16,7 +16,6 @@
package org.jetbrains.jet.lang.resolve.kotlin;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.descriptors.serialization.ClassId;
@@ -96,28 +95,28 @@ public final class DeserializedDescriptorResolver {
}
@Nullable
public ClassDescriptor resolveClass(@NotNull VirtualFile virtualFile) {
String[] data = readData(virtualFile);
public ClassDescriptor resolveClass(@NotNull KotlinJvmBinaryClass kotlinClass) {
String[] data = readData(kotlinClass);
return data == null ? null : new DeserializedClassDescriptor(storageManager, annotationDeserializer, javaDescriptorFinder,
JavaProtoBufUtil.readClassDataFrom(data));
}
@Nullable
public JetScope createKotlinPackageScope(@NotNull NamespaceDescriptor descriptor, @NotNull VirtualFile virtualFile) {
String[] data = readData(virtualFile);
public JetScope createKotlinPackageScope(@NotNull NamespaceDescriptor descriptor, @NotNull KotlinJvmBinaryClass kotlinClass) {
String[] data = readData(kotlinClass);
return data == null ? null : new DeserializedPackageMemberScope(storageManager, descriptor, annotationDeserializer,
javaDescriptorFinder, JavaProtoBufUtil.readPackageDataFrom(data));
}
@Nullable
private String[] readData(@NotNull VirtualFile virtualFile) {
KotlinClassFileHeader header = KotlinClassFileHeader.readKotlinHeaderFromClassFile(virtualFile);
private String[] readData(@NotNull KotlinJvmBinaryClass kotlinClass) {
KotlinClassFileHeader header = KotlinClassFileHeader.readKotlinHeaderFromClassFile(kotlinClass.getFile());
if (header instanceof SerializedDataHeader) {
return ((SerializedDataHeader) header).getAnnotationData();
}
if (header != null) {
errorReporter.reportIncompatibleAbiVersion(header.getFqName(), virtualFile, header.getVersion());
errorReporter.reportIncompatibleAbiVersion(header.getFqName(), kotlinClass.getFile(), header.getVersion());
}
return null;
@@ -16,13 +16,11 @@
package org.jetbrains.jet.lang.resolve.kotlin;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.resolve.name.FqName;
public interface VirtualFileFinder {
// TODO: support scope
public interface KotlinClassFinder {
@Nullable
VirtualFile find(@NotNull FqName className);
KotlinJvmBinaryClass find(@NotNull FqName fqName);
}
@@ -0,0 +1,25 @@
/*
* Copyright 2010-2013 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 org.jetbrains.jet.lang.resolve.kotlin;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
public interface KotlinJvmBinaryClass {
@NotNull
VirtualFile getFile();
}