Use VirtualFileFinder in JavaClassResolver

HACK: determine whether fqname is a name for class contained in class or namespace based on virtual file name
This commit introduces code duplication which is hard to avoid without major refactoring
This commit is contained in:
Pavel V. Talanov
2013-07-23 21:38:42 +04:00
parent 52de4215b5
commit e4988f9dba
4 changed files with 73 additions and 73 deletions
@@ -20,6 +20,7 @@ import com.intellij.openapi.project.Project;
import org.jetbrains.jet.lang.resolve.BindingTrace;
import org.jetbrains.jet.lang.resolve.java.JavaDescriptorResolver;
import org.jetbrains.jet.lang.resolve.java.PsiClassFinderImpl;
import org.jetbrains.jet.lang.resolve.java.vfilefinder.VirtualFileFinder;
import org.jetbrains.jet.lang.resolve.java.resolver.JavaClassResolver;
import org.jetbrains.jet.lang.resolve.java.resolver.JavaAnnotationResolver;
import org.jetbrains.jet.lang.resolve.java.resolver.JavaCompileTimeConstResolver;
@@ -43,6 +44,7 @@ public class InjectorForJavaDescriptorResolver {
private final BindingTrace bindingTrace;
private final JavaDescriptorResolver javaDescriptorResolver;
private final PsiClassFinderImpl psiClassFinder;
private final VirtualFileFinder virtualFileFinder;
private final JavaClassResolver javaClassResolver;
private final JavaAnnotationResolver javaAnnotationResolver;
private final JavaCompileTimeConstResolver javaCompileTimeConstResolver;
@@ -65,6 +67,7 @@ public class InjectorForJavaDescriptorResolver {
this.bindingTrace = bindingTrace;
this.javaDescriptorResolver = new JavaDescriptorResolver();
this.psiClassFinder = new PsiClassFinderImpl();
this.virtualFileFinder = com.intellij.openapi.components.ServiceManager.getService(project, VirtualFileFinder.class);
this.javaClassResolver = new JavaClassResolver();
this.javaAnnotationResolver = new JavaAnnotationResolver();
this.javaCompileTimeConstResolver = new JavaCompileTimeConstResolver();
@@ -96,6 +99,7 @@ public class InjectorForJavaDescriptorResolver {
javaClassResolver.setSignatureResolver(javaSignatureResolver);
javaClassResolver.setSupertypesResolver(javaSupertypeResolver);
javaClassResolver.setTrace(bindingTrace);
javaClassResolver.setVirtualFileFinder(virtualFileFinder);
javaAnnotationResolver.setClassResolver(javaClassResolver);
javaAnnotationResolver.setCompileTimeConstResolver(javaCompileTimeConstResolver);
@@ -31,6 +31,7 @@ import org.jetbrains.jet.lang.resolve.java.JavaBridgeConfiguration;
import org.jetbrains.jet.lang.resolve.java.JavaDescriptorResolver;
import org.jetbrains.jet.lang.resolve.java.PsiClassFinderImpl;
import org.jetbrains.jet.lang.resolve.NamespaceFactoryImpl;
import org.jetbrains.jet.lang.resolve.java.vfilefinder.VirtualFileFinder;
import org.jetbrains.jet.lang.resolve.DeclarationResolver;
import org.jetbrains.jet.lang.resolve.AnnotationResolver;
import org.jetbrains.jet.lang.resolve.calls.CallResolver;
@@ -81,6 +82,7 @@ public class InjectorForTopDownAnalyzerForJvm implements InjectorForTopDownAnaly
private final JavaDescriptorResolver javaDescriptorResolver;
private final PsiClassFinderImpl psiClassFinder;
private final NamespaceFactoryImpl namespaceFactory;
private final VirtualFileFinder virtualFileFinder;
private final DeclarationResolver declarationResolver;
private final AnnotationResolver annotationResolver;
private final CallResolver callResolver;
@@ -132,6 +134,7 @@ public class InjectorForTopDownAnalyzerForJvm implements InjectorForTopDownAnaly
this.javaDescriptorResolver = new JavaDescriptorResolver();
this.psiClassFinder = new PsiClassFinderImpl();
this.namespaceFactory = new NamespaceFactoryImpl();
this.virtualFileFinder = com.intellij.openapi.components.ServiceManager.getService(project, VirtualFileFinder.class);
this.declarationResolver = new DeclarationResolver();
this.annotationResolver = new AnnotationResolver();
this.callResolver = new CallResolver();
@@ -283,6 +286,7 @@ public class InjectorForTopDownAnalyzerForJvm implements InjectorForTopDownAnaly
javaClassResolver.setSignatureResolver(javaSignatureResolver);
javaClassResolver.setSupertypesResolver(javaSupertypeResolver);
javaClassResolver.setTrace(bindingTrace);
javaClassResolver.setVirtualFileFinder(virtualFileFinder);
javaAnnotationResolver.setClassResolver(javaClassResolver);
javaAnnotationResolver.setCompileTimeConstResolver(javaCompileTimeConstResolver);
@@ -36,6 +36,7 @@ import org.jetbrains.jet.lang.resolve.java.*;
import org.jetbrains.jet.lang.resolve.java.descriptor.ClassDescriptorFromJvmBytecode;
import org.jetbrains.jet.lang.resolve.java.sam.SingleAbstractMethodUtils;
import org.jetbrains.jet.lang.resolve.java.scope.JavaClassNonStaticMembersScope;
import org.jetbrains.jet.lang.resolve.java.vfilefinder.VirtualFileFinder;
import org.jetbrains.jet.lang.resolve.java.wrapper.PsiMethodWrapper;
import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lang.resolve.name.FqNameBase;
@@ -56,7 +57,6 @@ import java.util.*;
import static org.jetbrains.jet.lang.resolve.DescriptorResolver.createEnumClassObjectValueOfMethod;
import static org.jetbrains.jet.lang.resolve.DescriptorResolver.createEnumClassObjectValuesMethod;
import static org.jetbrains.jet.lang.resolve.DescriptorUtils.getClassObjectName;
import static org.jetbrains.jet.lang.resolve.java.resolver.DeserializedResolverUtils.getVirtualFile;
public final class JavaClassResolver {
@@ -91,10 +91,16 @@ public final class JavaClassResolver {
private JavaSupertypeResolver supertypesResolver;
private JavaFunctionResolver functionResolver;
private DeserializedDescriptorResolver kotlinDescriptorResolver;
private VirtualFileFinder virtualFileFinder;
public JavaClassResolver() {
}
@Inject
public void setVirtualFileFinder(VirtualFileFinder virtualFileFinder) {
this.virtualFileFinder = virtualFileFinder;
}
@Inject
public void setTrace(BindingTrace trace) {
this.trace = trace;
@@ -202,6 +208,30 @@ public final class JavaClassResolver {
}
private ClassDescriptor doResolveClass(@NotNull FqName qualifiedName, @NotNull PostponedTasks tasks) {
//TODO: correct scope
VirtualFile file = virtualFileFinder.find(qualifiedName);
if (file != null) {
//TODO: code duplication
//TODO: it is a hackish way to determine whether it is inner class or not
boolean isInnerClass = file.getName().contains("$");
ClassOrNamespaceDescriptor containingDeclaration = resolveParentDescriptor(qualifiedName, isInnerClass);
// class may be resolved during resolution of parent
ClassDescriptor cachedDescriptor = classDescriptorCache.get(javaClassToKotlinFqName(qualifiedName));
if (cachedDescriptor != null) {
return cachedDescriptor;
}
assert (!unresolvedCache.contains(qualifiedName))
: "We can resolve the class, so it can't be 'unresolved' during parent resolution";
ClassId id = ClassId.fromFqNameAndContainingDeclaration(qualifiedName, containingDeclaration);
ErrorReporter errorReporter = AbiVersionUtil.abiVersionErrorReporter(file, qualifiedName, trace);
ClassDescriptor deserializedDescriptor = kotlinDescriptorResolver.resolveClass(id, file, errorReporter);
if (deserializedDescriptor != null) {
cache(javaClassToKotlinFqName(qualifiedName), deserializedDescriptor);
return deserializedDescriptor;
}
}
PsiClass psiClass = psiClassFinder.findPsiClass(qualifiedName, PsiClassFinder.RuntimeClassesHandleMode.REPORT_ERROR);
if (psiClass == null) {
cacheNegativeValue(javaClassToKotlinFqName(qualifiedName));
@@ -213,8 +243,21 @@ public final class JavaClassResolver {
if (alreadyResolved != null) {
return alreadyResolved;
}
//TODO: code duplication
ClassOrNamespaceDescriptor containingDeclaration = resolveParentDescriptor(qualifiedName, isContainedInClass(psiClass));
// class may be resolved during resolution of parent
ClassDescriptor cachedDescriptor = classDescriptorCache.get(javaClassToKotlinFqName(qualifiedName));
if (cachedDescriptor != null) {
return cachedDescriptor;
}
assert (!unresolvedCache
.contains(qualifiedName)) : "We can resolve the class, so it can't be 'unresolved' during parent resolution";
return createJavaClassDescriptor(qualifiedName, psiClass, tasks);
checkFqNamesAreConsistent(psiClass, qualifiedName);
checkPsiClassIsNotJet(psiClass);
return doCreateClassDescriptor(qualifiedName, psiClass, tasks, containingDeclaration);
}
private void cacheNegativeValue(@NotNull FqNameBase qualifiedName) {
@@ -229,42 +272,6 @@ public final class JavaClassResolver {
return qualifiedName.asString().endsWith(JvmAbi.TRAIT_IMPL_SUFFIX);
}
@NotNull
private ClassDescriptor createJavaClassDescriptor(
@NotNull FqName fqName, @NotNull PsiClass psiClass,
@NotNull PostponedTasks taskList
) {
checkFqNamesAreConsistent(psiClass, fqName);
checkPsiClassIsNotJet(psiClass);
ClassOrNamespaceDescriptor containingDeclaration = resolveParentDescriptor(psiClass);
// class may be resolved during resolution of parent
ClassDescriptor cachedDescriptor = classDescriptorCache.get(javaClassToKotlinFqName(fqName));
if (cachedDescriptor != null) {
return cachedDescriptor;
}
assert (!unresolvedCache.contains(fqName)) : "We can resolve the class, so it can't be 'unresolved' during parent resolution";
VirtualFile outerClassFile = psiClass.getContainingFile().getVirtualFile();
if (outerClassFile != null) {
ClassId id = ClassId.fromFqNameAndContainingDeclaration(fqName, containingDeclaration);
VirtualFile file = getVirtualFile(id, outerClassFile);
if (file != null) {
ClassDescriptor deserializedDescriptor = kotlinDescriptorResolver.resolveClass(id, file,
DescriptorResolverUtils.createPsiBasedErrorReporter(psiClass, trace));
if (deserializedDescriptor != null) {
//TODO: class object and psi class
cache(javaClassToKotlinFqName(fqName), deserializedDescriptor);
return deserializedDescriptor;
}
}
}
return doCreateClassDescriptor(fqName, psiClass, taskList, containingDeclaration);
}
@NotNull
private ClassDescriptorFromJvmBytecode doCreateClassDescriptor(
@NotNull FqName fqName,
@@ -418,22 +425,25 @@ public final class JavaClassResolver {
}
@NotNull
private ClassOrNamespaceDescriptor resolveParentDescriptor(@NotNull PsiClass psiClass) {
if (isContainedInClass(psiClass)) {
return resolveParentClass(psiClass);
private ClassOrNamespaceDescriptor resolveParentDescriptor(@NotNull FqName childClassFQName, boolean isInnerClass) {
FqName parentFqName = childClassFQName.parent();
if (isInnerClass) {
ClassDescriptor parentClass = resolveClass(parentFqName, DescriptorSearchRule.INCLUDE_KOTLIN);
if (parentClass == null) {
throw new IllegalStateException("Could not resolve " + parentFqName + " required to be parent for " + childClassFQName);
}
return parentClass;
}
else {
return resolveParentNamespace(psiClass);
//TODO: why do we include kotlin here? what this flags means anyway?
NamespaceDescriptor parentNamespace = namespaceResolver.resolveNamespace(parentFqName, DescriptorSearchRule.INCLUDE_KOTLIN);
if (parentNamespace == null) {
throw new IllegalStateException("Could not resolve " + parentFqName + " required to be parent for " + childClassFQName);
}
return parentNamespace;
}
}
@NotNull
private static FqName getFqName(@NotNull PsiClass psiClass) {
String qualifiedName = psiClass.getQualifiedName();
assert qualifiedName != null;
return new FqName(qualifiedName);
}
// This method replaces "object" segments of FQ name to "<class-object-for-...>"
@NotNull
private static FqNameUnsafe javaClassToKotlinFqName(@NotNull FqName rawFqName) {
@@ -459,30 +469,6 @@ public final class JavaClassResolver {
return isContainedInClass(psiClass) && !psiClass.hasModifierProperty(PsiModifier.STATIC);
}
@NotNull
private ClassOrNamespaceDescriptor resolveParentClass(@NotNull PsiClass psiClass) {
PsiClass containingClass = psiClass.getContainingClass();
assert containingClass != null;
FqName containerFqName = getFqName(containingClass);
ClassDescriptor parentClass = resolveClass(containerFqName, DescriptorSearchRule.INCLUDE_KOTLIN);
if (parentClass == null) {
throw new IllegalStateException(
"PsiClass not found by name " + containerFqName + ", required to be container declaration of " + getFqName(psiClass));
}
return parentClass;
}
@NotNull
private ClassOrNamespaceDescriptor resolveParentNamespace(@NotNull PsiClass psiClass) {
FqName namespaceFqName = getFqName(psiClass).parent();
NamespaceDescriptor parentNamespace = namespaceResolver.resolveNamespace(namespaceFqName, DescriptorSearchRule.INCLUDE_KOTLIN);
if (parentNamespace == null) {
throw new IllegalStateException("cannot resolve namespace " + namespaceFqName +
", required to be container for " + getFqName(psiClass));
}
return parentNamespace;
}
@NotNull
private static ClassKind getClassKind(@NotNull PsiClass psiClass) {
if (psiClass.isInterface()) {