Call Hierarchy issue if a function is imported as an alias
Type: Bug
Behaviour
Expected vs. Actual
Call hierarchy of a function does not include calls of that function when imported as an alias.
Steps to reproduce:
Call Hierarchy is not working in python if the function was imported as another name:
from submodule import func as f
f()
Then call hierarchy of submodule.func() does not include f() call
Diagnostic data
- Python version (& distribution if applicable, e.g. Anaconda): 3.10.6
- Type of virtual environment used (e.g. conda, venv, virtualenv, etc.): Global
- Value of the
python.languageServersetting: Default
User Settings
Multiroot scenario, following user settings may not apply:
languageServer: "Pylance"
Extension version: 2022.12.1 VS Code version: Code 1.70.2 (e4503b30fc78200f846c62cf8091b76ff5547662, 2022-08-16T05:36:25.715Z) OS version: Linux x64 5.18.18-200.fc36.x86_64 Modes:
Need to investigate what typescript does in this case.
@erictraut, do you know if this is intentional for some reason?
Need to investigate what typescript does in this case.
Created Python repro:
# declare.py
def func():
return 1
# consume.py
from declare import func
from declare import func as f
def callByName():
func()
def callByAlias():
f()
And equivalent in TypeScript:
// declare.ts
export function func() {
return 1;
}
// consume.ts
import { func } from './declare';
import { func as f } from './declare';
function callByName() {
func();
}
function callByAlias() {
f();
}
Show Call Hierarchy
In Pylance, Show Call Hierarchy for func only shows the call to func in callByName:

In TypeScript, it also includes the call to f in callByAlias:

Find All References
In Pylance, Find All References on func does not include f:

In TypeScript, f is considered a reference and is included:

The "Find All References" behavior is intentional. The name must match exactly for it to be considered a reference. That's an important optimization. Without this, we would need to semantically evaluate every identifier in every file in the project, which would be prohibitively expensive in many cases.
The "Call Hierarchy" behavior looks inconsistent to me, so that's worth investigating. It's been a long time since I've looked at that code though, so my recollection is hazy.
The "Find All References" behavior is intentional. The name must match exactly for it to be considered a reference. That's an important optimization.
@erictraut, "Show Call Hierarchy" has a similar optimization -- https://github.com/microsoft/pyright/blob/main/packages/pyright-internal/src/languageService/callHierarchyProvider.ts#L318
Based on your comment above this seems like it's by design. Isn't "Show Call Hierarchy" for incoming calls roughly equivalent to "Find All References" on a function?
Yes, I agree with your analysis.
@RezaSR, as Eric explains above for "Find All References" it would be expensive for us to determine all the possible aliases for the target function. The same issue applies to "Show Call Hierarchy".
@debonte , thanks for your time.
it would be expensive for us
I see, and hopefully now I know this behavior. I was analyzing the structure of a program and some functions might be almost ignored, but luckily I noticed this by chance. I hope other users will be aware of this issue and not miss those functions.