pylance-release icon indicating copy to clipboard operation
pylance-release copied to clipboard

Call Hierarchy issue if a function is imported as an alias

Open RezaSR opened this issue 3 years ago • 1 comments

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.languageServer setting: 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:

RezaSR avatar Aug 23 '22 00:08 RezaSR

Need to investigate what typescript does in this case.

judej avatar Aug 23 '22 17:08 judej

@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: image

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

Find All References

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

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

debonte avatar Jan 30 '23 22:01 debonte

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.

erictraut avatar Jan 30 '23 23:01 erictraut

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?

debonte avatar Feb 01 '23 01:02 debonte

Yes, I agree with your analysis.

erictraut avatar Feb 01 '23 01:02 erictraut

@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 avatar Feb 01 '23 02:02 debonte

@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.

RezaSR avatar Feb 04 '23 22:02 RezaSR