Search classes by qualified name only in sources to prevent recursion
This commit is contained in:
+32
-5
@@ -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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+42
-36
@@ -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()] == '.')
|
||||||
|
|||||||
Reference in New Issue
Block a user