Search classes by qualified name only in sources to prevent recursion

This commit is contained in:
Nikolay Krasko
2014-02-06 20:50:13 +04:00
parent 064612f0f3
commit 2ef879ea3e
3 changed files with 83 additions and 41 deletions
@@ -32,15 +32,19 @@ import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns
import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.diagnostic.Logger
import org.jetbrains.jet.lang.resolve.java.structure.impl.JavaClassImpl import org.jetbrains.jet.lang.resolve.java.structure.impl.JavaClassImpl
import com.google.common.base.Predicates
import org.jetbrains.jet.lang.descriptors.impl.PackageViewDescriptorImpl
import org.jetbrains.jet.lang.resolve.name.tail
import org.jetbrains.jet.lang.resolve.name.each
public class LazyResolveBasedCache() : JavaResolverCache { public class LazyResolveBasedCache() : JavaResolverCache {
private var resolveSession by Delegates.notNull<ResolveSession>()
private var traceBasedCache = TraceBasedJavaResolverCache()
class object { class object {
private val LOG = Logger.getInstance(javaClass<TraceBasedJavaResolverCache>()) private val LOG = Logger.getInstance(javaClass<TraceBasedJavaResolverCache>())
} }
private var resolveSession by Delegates.notNull<ResolveSession>()
private val traceBasedCache = TraceBasedJavaResolverCache()
Inject Inject
public fun setSession(resolveSession: ResolveSession) { public fun setSession(resolveSession: ResolveSession) {
this.resolveSession = resolveSession this.resolveSession = resolveSession
@@ -51,8 +55,11 @@ public class LazyResolveBasedCache() : JavaResolverCache {
val descriptor = traceBasedCache.getClassResolvedFromSource(fqName) val descriptor = traceBasedCache.getClassResolvedFromSource(fqName)
if (descriptor != null) return descriptor if (descriptor != null) return descriptor
val classes = ResolveSessionUtils.getClassDescriptorsByFqName(resolveSession, fqName) return resolveSession.findInPackageFragments(fqName) { packageFragmentDescriptor ->
return if (classes.isNotEmpty()) classes.first() else null ResolveSessionUtils.findByQualifiedName(
packageFragmentDescriptor.getMemberScope(),
fqName.tail(packageFragmentDescriptor.getFqName()))
}
} }
override fun getClass(javaClass: JavaClass): ClassDescriptor? { override fun getClass(javaClass: JavaClass): ClassDescriptor? {
@@ -73,4 +80,24 @@ public class LazyResolveBasedCache() : JavaResolverCache {
override fun recordClass(javaClass: JavaClass, descriptor: ClassDescriptor) { override fun recordClass(javaClass: JavaClass, descriptor: ClassDescriptor) {
traceBasedCache.recordClass(javaClass, descriptor) traceBasedCache.recordClass(javaClass, descriptor)
} }
private fun <T: Any> ResolveSession.findInPackageFragments(fqName: FqName, find: (PackageFragmentDescriptor) -> T?): T? {
var result: T? = null
(if (fqName.isRoot()) fqName else fqName.parent()).each { (parentFqName: FqName) : Boolean ->
val packageDescriptor = resolveSession.getPackageFragment(parentFqName)
if (packageDescriptor == null) {
return@each false // Stop iteration
}
val findResult = find(packageDescriptor)
if (findResult != null) {
result = findResult
return@each false // Stop iteration
}
true // Continue search
}
return result
}
} }
@@ -16,13 +16,12 @@
package org.jetbrains.jet.lang.resolve.lazy; package org.jetbrains.jet.lang.resolve.lazy;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.intellij.util.containers.Predicate;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor; import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.descriptors.ClassifierDescriptor;
import org.jetbrains.jet.lang.descriptors.PackageViewDescriptor;
import org.jetbrains.jet.lang.psi.JetNamed; import org.jetbrains.jet.lang.psi.JetNamed;
import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lang.resolve.name.Name; import org.jetbrains.jet.lang.resolve.name.Name;
@@ -44,14 +43,16 @@ public class ResolveSessionUtils {
public static final Predicate<ClassDescriptor> NON_SINGLETON_FILTER = new Predicate<ClassDescriptor>() { public static final Predicate<ClassDescriptor> NON_SINGLETON_FILTER = new Predicate<ClassDescriptor>() {
@Override @Override
public boolean apply(ClassDescriptor descriptor) { public boolean apply(@Nullable ClassDescriptor descriptor) {
assert descriptor != null;
return !descriptor.getKind().isSingleton(); return !descriptor.getKind().isSingleton();
} }
}; };
public static final Predicate<ClassDescriptor> SINGLETON_FILTER = new Predicate<ClassDescriptor>() { public static final Predicate<ClassDescriptor> SINGLETON_FILTER = new Predicate<ClassDescriptor>() {
@Override @Override
public boolean apply(ClassDescriptor descriptor) { public boolean apply(@Nullable ClassDescriptor descriptor) {
assert descriptor != null;
return descriptor.getKind().isSingleton(); return descriptor.getKind().isSingleton();
} }
}; };
@@ -70,9 +71,7 @@ public class ResolveSessionUtils {
@NotNull FqName fqName, @NotNull FqName fqName,
@NotNull Predicate<ClassDescriptor> filter @NotNull Predicate<ClassDescriptor> filter
) { ) {
if (fqName.isRoot()) { if (fqName.isRoot()) return Collections.emptyList();
return Collections.emptyList();
}
Collection<ClassDescriptor> classDescriptors = Lists.newArrayList(); Collection<ClassDescriptor> classDescriptors = Lists.newArrayList();
@@ -81,8 +80,10 @@ public class ResolveSessionUtils {
PackageViewDescriptor packageDescriptor = analyzer.getModuleDescriptor().getPackage(packageFqName); PackageViewDescriptor packageDescriptor = analyzer.getModuleDescriptor().getPackage(packageFqName);
if (packageDescriptor != null) { if (packageDescriptor != null) {
FqName classInPackagePath = NamePackage.tail(fqName, packageFqName); FqName classInPackagePath = NamePackage.tail(fqName, packageFqName);
Collection<ClassDescriptor> descriptors = getClassOrObjectDescriptorsByFqName(packageDescriptor, classInPackagePath, filter); ClassDescriptor classDescriptor = findByQualifiedName(packageDescriptor.getMemberScope(), classInPackagePath, filter);
classDescriptors.addAll(descriptors); if (classDescriptor != null) {
classDescriptors.add(classDescriptor);
}
} }
if (packageFqName.isRoot()) { if (packageFqName.isRoot()) {
@@ -96,42 +97,47 @@ public class ResolveSessionUtils {
return classDescriptors; return classDescriptors;
} }
@NotNull @Nullable
private static Collection<ClassDescriptor> getClassOrObjectDescriptorsByFqName( public static ClassDescriptor findByQualifiedName(@NotNull JetScope packageScope, @NotNull FqName path) {
@NotNull PackageViewDescriptor packageDescriptor, return findByQualifiedName(packageScope, path, Predicates.<ClassDescriptor>alwaysTrue());
}
@Nullable
private static ClassDescriptor findByQualifiedName(
@NotNull JetScope jetScope,
@NotNull FqName path, @NotNull FqName path,
@NotNull Predicate<ClassDescriptor> filter @NotNull Predicate<ClassDescriptor> filter
) { ) {
if (path.isRoot()) { if (path.isRoot()) return null;
return Collections.emptyList();
}
Collection<JetScope> scopes = Arrays.asList(packageDescriptor.getMemberScope()); if (NamePackage.isOneSegmentFQN(path)) {
Name shortName = path.shortName();
ClassifierDescriptor classifier = jetScope.getClassifier(shortName);
if (classifier instanceof ClassDescriptor) {
ClassDescriptor resultDescriptor = (ClassDescriptor) classifier;
List<Name> names = path.pathSegments(); if (filter.apply(resultDescriptor)) {
if (names.size() > 1) { return resultDescriptor;
for (Name subName : path.pathSegments().subList(0, names.size() - 1)) {
Collection<JetScope> tempScopes = Lists.newArrayList();
for (JetScope scope : scopes) {
ClassifierDescriptor classifier = scope.getClassifier(subName);
if (classifier instanceof ClassDescriptor) {
tempScopes.add(((ClassDescriptor) classifier).getUnsubstitutedInnerClassesScope());
}
} }
scopes = tempScopes;
} }
return null;
} }
Name shortName = path.shortName(); Name firstName = NamePackage.getFirstSegment(path);
Collection<ClassDescriptor> resultClassifierDescriptors = Lists.newArrayList();
for (JetScope scope : scopes) { // Search in internal class
ClassifierDescriptor classifier = scope.getClassifier(shortName); ClassifierDescriptor classifier = jetScope.getClassifier(firstName);
if (classifier instanceof ClassDescriptor && filter.apply((ClassDescriptor) classifier)) { if (classifier instanceof ClassDescriptor) {
resultClassifierDescriptors.add((ClassDescriptor) classifier); return findByQualifiedName(
} ((ClassDescriptor) classifier).getUnsubstitutedInnerClassesScope(),
NamePackage.withoutFirstSegment(path),
filter);
} }
return resultClassifierDescriptors; // TODO: search in class object
return null;
} }
@NotNull @NotNull
@@ -112,6 +112,15 @@ public fun isValidJavaFqName(qualifiedName: String?): Boolean {
return state != State.AFTER_DOT return state != State.AFTER_DOT
} }
public fun FqName.getFirstSegment(): Name = this.pathSegments().first()
tailRecursive
public fun FqName.each(operation: (FqName) -> Boolean) {
if (operation(this) && !isRoot()) {
parent().each(operation)
}
}
private fun isSubpackageOf(subpackageNameStr: String, packageNameStr: String): Boolean { private fun isSubpackageOf(subpackageNameStr: String, packageNameStr: String): Boolean {
return subpackageNameStr == packageNameStr || return subpackageNameStr == packageNameStr ||
(subpackageNameStr.startsWith(packageNameStr) && subpackageNameStr[packageNameStr.length()] == '.') (subpackageNameStr.startsWith(packageNameStr) && subpackageNameStr[packageNameStr.length()] == '.')