mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
PY-89956 resolve local variable via PyDefUseUtil.getLatestDefs instead of PyResolveUtil.scopeCrawlUp
When a name is defined in the reference's own scope, scopeCrawlUp collects all same-name definitions just to find the owner and then narrows to the reaching defs anyway; for a variable reassigned N times that makes resolving its N references O(N^2) and hangs inspection. Go straight to the control-flow reaching defs for the plain local case; everything else falls back to the general path unchanged. GitOrigin-RevId: 3694fdb0afd6077340e1d75eaf39090fe1f848a9
This commit is contained in:
committed by
intellij-monorepo-bot
parent
56f68c7cf0
commit
b8a042e663
@@ -52,6 +52,9 @@ public interface Scope {
|
||||
|
||||
boolean containsDeclaration(String name);
|
||||
|
||||
/** Cheap O(1) check whether this scope itself declares a (non-import) named element {@code name}. */
|
||||
boolean declaresName(@NotNull String name);
|
||||
|
||||
@NotNull
|
||||
List<PyImportedNameDefiner> getImportedNameDefiners();
|
||||
|
||||
|
||||
+8
@@ -169,6 +169,14 @@ public class ScopeImpl implements Scope {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean declaresName(@NotNull String name) {
|
||||
if (myNamedElements == null) {
|
||||
collectDeclarations();
|
||||
}
|
||||
return myNamedElements.containsKey(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull List<PyImportedNameDefiner> getImportedNameDefiners() {
|
||||
if (myImportedNameDefiners == null) {
|
||||
|
||||
+18
@@ -274,6 +274,24 @@ public class PyReferenceImpl implements PsiReferenceEx, PsiPolyVariantReference
|
||||
return ((PyFile)realContext).multiResolveName(referencedName);
|
||||
}
|
||||
|
||||
// PY-89956 fast path: for a plain local variable, resolve straight to its control-flow
|
||||
// reaching definitions instead of first collecting *all* same-name definitions of the scope
|
||||
final TypeEvalContext typeEvalContext = myContext.getTypeEvalContext();
|
||||
final ScopeOwner owner = ScopeUtil.getScopeOwner(realContext);
|
||||
if (typeEvalContext.maySwitchToAST(realContext) && owner != null && !(owner instanceof PyClass)) {
|
||||
final Scope scope = ControlFlowCache.getScope(owner);
|
||||
if (scope.declaresName(referencedName) && !scope.isGlobal(referencedName) && !scope.isNonlocal(referencedName)) {
|
||||
final List<Instruction> defs =
|
||||
PyDefUseUtil.getLatestDefs(owner, referencedName, realContext, false, true, typeEvalContext).defs();
|
||||
if (!defs.isEmpty() && ContainerUtil.and(defs, i -> i.getElement() instanceof PyTargetExpression)) {
|
||||
final ResolveResultList latest = resolveToLatestDefs(defs, realContext, referencedName, typeEvalContext);
|
||||
if (!latest.isEmpty()) {
|
||||
return latest;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// here we have an unqualified expr. it may be defined:
|
||||
// ...in current file
|
||||
final PyResolveProcessor processor = new PyResolveProcessor(referencedName);
|
||||
|
||||
Reference in New Issue
Block a user