Skip to content

Commit

Permalink
PERF: optimize "find usages" of associated values
Browse files Browse the repository at this point in the history
Works for e.g. functions in inherent impls or
trait impls. Greatly speeds up find usages of
`Foo::new` functions. Fixes #4222
  • Loading branch information
vlad20012 committed Dec 19, 2019
1 parent d269f46 commit 16652e6
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 15 deletions.
12 changes: 6 additions & 6 deletions src/main/kotlin/org/rust/lang/core/psi/ext/RsAbstractable.kt
Expand Up @@ -43,17 +43,17 @@ inline fun RsAbstractable.getOwner(getAncestor: PsiElement.() -> PsiElement?): R
// Resolve a const, fn or type in a impl block to the corresponding item in the trait block
val RsAbstractable.superItem: RsAbstractable?
get() {
val rustImplItem = ancestorStrict<RsImplItem>() ?: return null
val superTrait = rustImplItem.traitRef?.resolveToTrait() ?: return null
val impl = (owner as? RsAbstractableOwner.Impl)?.impl ?: return null
val superTrait = impl.traitRef?.resolveToTrait() ?: return null
return superTrait.findCorrespondingElement(this)
}

fun RsTraitOrImpl.findCorrespondingElement(element: RsAbstractable): RsAbstractable? {
val members = members ?: return null
val members = expandedMembers
return when (element) {
is RsConstant -> members.constantList.find { it.name == element.name }
is RsFunction -> members.functionList.find { it.name == element.name }
is RsTypeAlias -> members.typeAliasList.find { it.name == element.name }
is RsConstant -> members.constants.find { it.name == element.name }
is RsFunction -> members.functions.find { it.name == element.name }
is RsTypeAlias -> members.types.find { it.name == element.name }
else -> error("unreachable")
}
}
Expand Up @@ -30,18 +30,46 @@ class RsPathReferenceImpl(

override val RsPath.referenceAnchor: PsiElement get() = referenceNameElement

override fun isReferenceTo(element: PsiElement): Boolean {
if (element is RsFieldDecl) return false
override fun isReferenceTo(target: PsiElement): Boolean {
if (target is RsFieldDecl) return false

val path = this.element
if (element is RsNamedElement && !path.allowedNamespaces().intersects(element.namespaces)) return false
if (target is RsNamedElement && !path.allowedNamespaces().intersects(target.namespaces)) return false

val isMember = element is RsAbstractable && element.owner.isImplOrTrait
if (isMember && (path.parent is RsUseSpeck || path.path == null && path.typeQual == null)) {
return false
if (target is RsAbstractable) {
val owner = target.owner
if (owner.isImplOrTrait && (path.parent is RsUseSpeck || path.path == null && path.typeQual == null)) {
return false
}

// If `path.parent` is expression, then `path.reference.resolve()` will invoke type inference for the
// function containing `path`, which can be very heavy. Trying to avoid it
if (target !is RsTypeAlias && path.parent is RsPathExpr) {
val resolvedRaw = resolvePathRaw(path)
val mgr = target.manager
when (owner) {
RsAbstractableOwner.Free, RsAbstractableOwner.Foreign ->
return resolvedRaw.any { mgr.areElementsEquivalent(it.element, target) }
is RsAbstractableOwner.Impl -> if (owner.isInherent) {
return resolvedRaw.any { mgr.areElementsEquivalent(it.element, target) }
} else {
if (resolvedRaw.size == 1 && mgr.areElementsEquivalent(resolvedRaw.single().element, target)) return true
val superItem = target.superItem ?: return false
val canBeReferenceTo = resolvedRaw.any {
mgr.areElementsEquivalent(it.element, target) ||
mgr.areElementsEquivalent(it.element, superItem)
}
if (!canBeReferenceTo) return false
}
is RsAbstractableOwner.Trait -> {
val canBeReferenceTo = resolvedRaw.any { mgr.areElementsEquivalent(it.element, target) }
if (!canBeReferenceTo) return false
}
}
}
}
val target = resolve()
return element.manager.areElementsEquivalent(target, element)
val resolved = resolve()
return target.manager.areElementsEquivalent(resolved, target)
}

override fun advancedResolve(): BoundElement<RsElement>? =
Expand Down Expand Up @@ -74,7 +102,7 @@ class RsPathReferenceImpl(
}
}

fun resolvePathRaw(path: RsPath, lookup: ImplLookup): List<ScopeEntry> {
fun resolvePathRaw(path: RsPath, lookup: ImplLookup? = null): List<ScopeEntry> {
return collectResolveVariantsAsScopeEntries(path.referenceName) {
processPathResolveVariants(lookup, path, false, it)
}
Expand Down

0 comments on commit 16652e6

Please sign in to comment.