diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/LazyResolveBasedCache.kt b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/LazyResolveBasedCache.kt index 06466d7614c..7a78f8c0595 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/LazyResolveBasedCache.kt +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/resolver/LazyResolveBasedCache.kt @@ -32,15 +32,19 @@ import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.diagnostic.Logger 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 { - private var resolveSession by Delegates.notNull() - private var traceBasedCache = TraceBasedJavaResolverCache() - class object { private val LOG = Logger.getInstance(javaClass()) } + private var resolveSession by Delegates.notNull() + private val traceBasedCache = TraceBasedJavaResolverCache() + Inject public fun setSession(resolveSession: ResolveSession) { this.resolveSession = resolveSession @@ -51,8 +55,11 @@ public class LazyResolveBasedCache() : JavaResolverCache { val descriptor = traceBasedCache.getClassResolvedFromSource(fqName) if (descriptor != null) return descriptor - val classes = ResolveSessionUtils.getClassDescriptorsByFqName(resolveSession, fqName) - return if (classes.isNotEmpty()) classes.first() else null + return resolveSession.findInPackageFragments(fqName) { packageFragmentDescriptor -> + ResolveSessionUtils.findByQualifiedName( + packageFragmentDescriptor.getMemberScope(), + fqName.tail(packageFragmentDescriptor.getFqName())) + } } override fun getClass(javaClass: JavaClass): ClassDescriptor? { @@ -73,4 +80,24 @@ public class LazyResolveBasedCache() : JavaResolverCache { override fun recordClass(javaClass: JavaClass, descriptor: ClassDescriptor) { traceBasedCache.recordClass(javaClass, descriptor) } + + private fun 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 + } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/ResolveSessionUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/ResolveSessionUtils.java index 9daae950242..8cba29557e4 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/ResolveSessionUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/ResolveSessionUtils.java @@ -16,13 +16,12 @@ 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.intellij.util.containers.Predicate; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.jet.lang.descriptors.ClassDescriptor; -import org.jetbrains.jet.lang.descriptors.ClassifierDescriptor; -import org.jetbrains.jet.lang.descriptors.PackageViewDescriptor; +import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.psi.JetNamed; import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.lang.resolve.name.Name; @@ -44,14 +43,16 @@ public class ResolveSessionUtils { public static final Predicate NON_SINGLETON_FILTER = new Predicate() { @Override - public boolean apply(ClassDescriptor descriptor) { + public boolean apply(@Nullable ClassDescriptor descriptor) { + assert descriptor != null; return !descriptor.getKind().isSingleton(); } }; public static final Predicate SINGLETON_FILTER = new Predicate() { @Override - public boolean apply(ClassDescriptor descriptor) { + public boolean apply(@Nullable ClassDescriptor descriptor) { + assert descriptor != null; return descriptor.getKind().isSingleton(); } }; @@ -70,9 +71,7 @@ public class ResolveSessionUtils { @NotNull FqName fqName, @NotNull Predicate filter ) { - if (fqName.isRoot()) { - return Collections.emptyList(); - } + if (fqName.isRoot()) return Collections.emptyList(); Collection classDescriptors = Lists.newArrayList(); @@ -81,8 +80,10 @@ public class ResolveSessionUtils { PackageViewDescriptor packageDescriptor = analyzer.getModuleDescriptor().getPackage(packageFqName); if (packageDescriptor != null) { FqName classInPackagePath = NamePackage.tail(fqName, packageFqName); - Collection descriptors = getClassOrObjectDescriptorsByFqName(packageDescriptor, classInPackagePath, filter); - classDescriptors.addAll(descriptors); + ClassDescriptor classDescriptor = findByQualifiedName(packageDescriptor.getMemberScope(), classInPackagePath, filter); + if (classDescriptor != null) { + classDescriptors.add(classDescriptor); + } } if (packageFqName.isRoot()) { @@ -96,42 +97,47 @@ public class ResolveSessionUtils { return classDescriptors; } - @NotNull - private static Collection getClassOrObjectDescriptorsByFqName( - @NotNull PackageViewDescriptor packageDescriptor, + @Nullable + public static ClassDescriptor findByQualifiedName(@NotNull JetScope packageScope, @NotNull FqName path) { + return findByQualifiedName(packageScope, path, Predicates.alwaysTrue()); + } + + @Nullable + private static ClassDescriptor findByQualifiedName( + @NotNull JetScope jetScope, @NotNull FqName path, @NotNull Predicate filter ) { - if (path.isRoot()) { - return Collections.emptyList(); - } + if (path.isRoot()) return null; - Collection 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 names = path.pathSegments(); - if (names.size() > 1) { - for (Name subName : path.pathSegments().subList(0, names.size() - 1)) { - Collection tempScopes = Lists.newArrayList(); - for (JetScope scope : scopes) { - ClassifierDescriptor classifier = scope.getClassifier(subName); - if (classifier instanceof ClassDescriptor) { - tempScopes.add(((ClassDescriptor) classifier).getUnsubstitutedInnerClassesScope()); - } + if (filter.apply(resultDescriptor)) { + return resultDescriptor; } - scopes = tempScopes; } + + return null; } - Name shortName = path.shortName(); - Collection resultClassifierDescriptors = Lists.newArrayList(); - for (JetScope scope : scopes) { - ClassifierDescriptor classifier = scope.getClassifier(shortName); - if (classifier instanceof ClassDescriptor && filter.apply((ClassDescriptor) classifier)) { - resultClassifierDescriptors.add((ClassDescriptor) classifier); - } + Name firstName = NamePackage.getFirstSegment(path); + + // Search in internal class + ClassifierDescriptor classifier = jetScope.getClassifier(firstName); + if (classifier instanceof ClassDescriptor) { + return findByQualifiedName( + ((ClassDescriptor) classifier).getUnsubstitutedInnerClassesScope(), + NamePackage.withoutFirstSegment(path), + filter); } - return resultClassifierDescriptors; + // TODO: search in class object + + return null; } @NotNull diff --git a/core/descriptors/src/org/jetbrains/jet/lang/resolve/name/FqNamesUtil.kt b/core/descriptors/src/org/jetbrains/jet/lang/resolve/name/FqNamesUtil.kt index 5e7754269b0..abdabdbe3ae 100644 --- a/core/descriptors/src/org/jetbrains/jet/lang/resolve/name/FqNamesUtil.kt +++ b/core/descriptors/src/org/jetbrains/jet/lang/resolve/name/FqNamesUtil.kt @@ -112,6 +112,15 @@ public fun isValidJavaFqName(qualifiedName: String?): Boolean { 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 { return subpackageNameStr == packageNameStr || (subpackageNameStr.startsWith(packageNameStr) && subpackageNameStr[packageNameStr.length()] == '.')