Change import resolution algorithm

The new algorithm: move from right to left, trying to find package, (new code) when found go right resolving descriptors (uses old code)
This allows to avoid unnecessary computations (matters in IDE moslty) for resolving root packages
This changes semantics of imports resolution: when package clashes with any declaration package is preffered
This commit is contained in:
Pavel V. Talanov
2015-05-13 21:21:40 +03:00
parent 7b0458f1a9
commit 257b8f31e7
2 changed files with 89 additions and 19 deletions
@@ -21,11 +21,10 @@ import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.PackageViewDescriptor import org.jetbrains.kotlin.descriptors.PackageViewDescriptor
import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.psi.JetImportDirective import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.JetPsiUtil import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.JetQualifiedExpression
import org.jetbrains.kotlin.psi.JetSimpleNameExpression
import org.jetbrains.kotlin.resolve.scopes.JetScope import org.jetbrains.kotlin.resolve.scopes.JetScope
import java.util.ArrayList
import kotlin.platform.platformStatic import kotlin.platform.platformStatic
public class ImportDirectiveProcessor( public class ImportDirectiveProcessor(
@@ -44,20 +43,11 @@ public class ImportDirectiveProcessor(
} }
val importedReference = importDirective.getImportedReference() ?: return JetScope.Empty val importedReference = importDirective.getImportedReference() ?: return JetScope.Empty
val importPath = importDirective.getImportPath() ?: return JetScope.Empty
val scope = JetModuleUtil.getImportsResolutionScope(moduleDescriptor, allowClassesFromDefaultPackage) val (packageViewDescriptor, selectorsToLookUp) = tryResolvePackagesFromRightToLeft(
val descriptors = if (importedReference is JetQualifiedExpression) { moduleDescriptor, trace, importPath.fqnPart(), importedReference
//store result only when we find all descriptors, not only classes on the second phase )
qualifiedExpressionResolver.lookupDescriptorsForQualifiedExpression( val descriptors = lookUpMembersFromLeftToRight(moduleDescriptor, trace, packageViewDescriptor, selectorsToLookUp, lookupMode)
importedReference, scope, moduleDescriptor, trace, lookupMode, lookupMode.isEverything()
)
}
else {
assert(importedReference is JetSimpleNameExpression)
qualifiedExpressionResolver.lookupDescriptorsForSimpleNameReference(
importedReference as JetSimpleNameExpression, scope, moduleDescriptor, trace, lookupMode, true, lookupMode.isEverything()
)
}
val referenceExpression = JetPsiUtil.getLastReference(importedReference) val referenceExpression = JetPsiUtil.getLastReference(importedReference)
if (importDirective.isAllUnder()) { if (importDirective.isAllUnder()) {
@@ -82,6 +72,86 @@ public class ImportDirectiveProcessor(
} }
} }
private fun tryResolvePackagesFromRightToLeft(
moduleDescriptor: ModuleDescriptor,
trace: BindingTrace,
fqName: FqName,
jetExpression: JetExpression?
): Pair<PackageViewDescriptor, List<JetSimpleNameExpression>> {
val selectorsToLookUp = ArrayList<JetSimpleNameExpression>()
fun recTryResolvePackagesFromRightToLeft(
fqName: FqName,
jetExpression: JetExpression?
): PackageViewDescriptor {
val packageView = moduleDescriptor.getPackage(fqName)
if (jetExpression == null) {
assert(fqName.isRoot())
return packageView.sure { "Root package does not exist in module $moduleDescriptor" }
}
return when {
packageView != null -> {
recordPackageViews(jetExpression, packageView, trace)
packageView
}
else -> {
assert(!fqName.isRoot())
val (expressionRest, selector) = jetExpression.getReceiverAndSelector()
if (selector != null) {
selectorsToLookUp.add(selector)
}
recTryResolvePackagesFromRightToLeft(fqName.parent(), expressionRest)
}
}
}
val packageView = recTryResolvePackagesFromRightToLeft(fqName, jetExpression)
return Pair(packageView, selectorsToLookUp.reverse())
}
private fun recordPackageViews(jetExpression: JetExpression, packageView: PackageViewDescriptor, trace: BindingTrace) {
trace.record(BindingContext.REFERENCE_TARGET, JetPsiUtil.getLastReference(jetExpression), packageView)
val containingView = packageView.getContainingDeclaration()
val (receiver, _) = jetExpression.getReceiverAndSelector()
if (containingView != null && receiver != null) {
recordPackageViews(receiver, containingView, trace)
}
}
private fun lookUpMembersFromLeftToRight(
moduleDescriptor: ModuleDescriptor,
trace: BindingTrace,
packageView: PackageViewDescriptor,
selectorsToLookUp: List<JetSimpleNameExpression>,
lookupMode: QualifiedExpressionResolver.LookupMode
): Collection<DeclarationDescriptor> {
var currentDescriptors: Collection<DeclarationDescriptor> = listOf(packageView)
for ((i, selector) in selectorsToLookUp.withIndex()) {
currentDescriptors = qualifiedExpressionResolver.lookupSelectorDescriptors(
selector, currentDescriptors, trace, moduleDescriptor, lookupMode, lookupMode.isEverything()
)
val isLastReference = i == selectorsToLookUp.size() - 1
if (!isLastReference && !canImportMembersFrom(currentDescriptors, selector, trace, lookupMode)) {
return emptyList()
}
}
return currentDescriptors
}
private fun JetExpression.getReceiverAndSelector(): Pair<JetExpression?, JetSimpleNameExpression?> {
when (this) {
is JetDotQualifiedExpression -> {
return Pair(this.getReceiverExpression(), this.getSelectorExpression() as? JetSimpleNameExpression)
}
is JetSimpleNameExpression -> {
return Pair(null, this)
}
else -> {
throw AssertionError("Invalid expression in import $this of class ${this.javaClass}")
}
}
}
public companion object { public companion object {
public fun canAllUnderImportFrom(descriptors: Collection<DeclarationDescriptor>): Boolean { public fun canAllUnderImportFrom(descriptors: Collection<DeclarationDescriptor>): Boolean {
if (descriptors.isEmpty()) { if (descriptors.isEmpty()) {
@@ -171,7 +171,7 @@ public class QualifiedExpressionResolver {
} }
@NotNull @NotNull
private Collection<DeclarationDescriptor> lookupSelectorDescriptors( public Collection<DeclarationDescriptor> lookupSelectorDescriptors(
@NotNull JetSimpleNameExpression selector, @NotNull JetSimpleNameExpression selector,
@NotNull Collection<DeclarationDescriptor> declarationDescriptors, @NotNull Collection<DeclarationDescriptor> declarationDescriptors,
@NotNull BindingTrace trace, @NotNull BindingTrace trace,