Skip to content

impl Class Hierarchy #2207 - #2687

Open
asukaminato0721 wants to merge 4 commits into
meta:mainfrom
asukaminato0721:2207-4972
Open

asukaminato0721 wants to merge 4 commits into
meta:mainfrom
asukaminato0721:2207-4972

Conversation

@asukaminato0721

Copy link
Copy Markdown
Collaborator

Summary

Fixes part of #2207

ref microsoft/pylance-release#4972 (comment)

Added a client-side Python CodeLens provider that shows:
- $(arrow-up) Overrides ... on overriding methods
- $(arrow-down) Implemented by ... / implementation counts on parent methods
Registered the provider plus navigation/quick-pick commands

Implemented the provider

Test Plan

Added backend regression coverage for that parent-resolution path

@meta-cla meta-cla Bot added the cla signed label Mar 6, 2026
@github-actions

This comment has been minimized.

@asukaminato0721
asukaminato0721 marked this pull request as ready for review March 6, 2026 14:51
Copilot AI review requested due to automatic review settings March 6, 2026 14:51

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds an overrides/implementations CodeLens experience for Python in the VS Code extension and extends the backend go-to-declaration behavior so overriding members can navigate to the overridden parent declaration (supporting class hierarchy/navigation work tracked in #2207).

Changes:

  • Added a new VS Code OverrideCodeLensProvider that shows “Overrides …” and “Implemented by …” lenses based on declaration/implementation providers.
  • Registered the provider and navigation/quick-pick commands in the extension activation flow.
  • Updated backend goto_declaration to redirect overriding members to parent declarations, and added regression tests for method + class attribute overrides.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 6 comments.

File Description
pyrefly/lib/test/lsp/definition.rs Adds tests validating go-to-declaration jumps from overrides to parent declarations.
pyrefly/lib/state/lsp.rs Adds override-parent lookup logic to goto_declaration plus a helper for resolving module info from a ModulePath.
lsp/src/overrideCodeLens.ts Implements the CodeLens provider and navigation commands for override/implementation targets.
lsp/src/extension.ts Registers the CodeLens provider, hooks refreshes, and registers navigation commands.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Comment thread lsp/src/overrideCodeLens.ts Resolved
Comment thread lsp/src/overrideCodeLens.ts Resolved
Comment thread lsp/src/extension.ts
Comment on lines +229 to +235
context.subscriptions.push(
workspace.onDidChangeTextDocument(event => {
if (event.document.languageId === 'python') {
overrideCodeLensProvider.refresh();
}
}),
);

Copilot AI Mar 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refreshing CodeLenses on every onDidChangeTextDocument for Python means this provider will re-run (and potentially issue many LSP requests) on every keystroke. Consider debouncing this refresh (timer-based) and/or refreshing only on saves / when the edited document is the active editor to reduce churn.

Copilot uses AI. Check for mistakes.
Comment thread pyrefly/lib/state/lsp.rs Outdated
Comment on lines +2005 to +2019
fn parent_declarations_for_definition(
&self,
handle: &Handle,
definition: &TextRangeWithModule,
) -> Vec<TextRangeWithModule> {
let Some(index) = self
.get_solutions(handle)
.and_then(|solutions| solutions.get_index())
else {
return Vec::new();
};
let Some(parent_methods) = index
.lock()
.parent_methods_map
.get(&definition.range)

Copilot AI Mar 6, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

parent_declarations_for_definition always reads the solutions index for the current handle, but it looks up overrides by definition.range (a TextRange without module identity). If find_definition returns a definition in another module (e.g. imports/stubs), this can either miss the override info or accidentally match an unrelated range in the current module and return incorrect parent declarations. Consider only applying this override-redirect when definition.module.path() matches the current module, or resolve the correct handle/index for definition.module before consulting parent_methods_map.

Copilot uses AI. Check for mistakes.
Comment thread pyrefly/lib/state/lsp.rs Resolved
Comment thread pyrefly/lib/state/lsp.rs Resolved
@asukaminato0721
asukaminato0721 marked this pull request as draft March 6, 2026 19:21
@asukaminato0721
asukaminato0721 marked this pull request as ready for review March 6, 2026 19:37
@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions github-actions Bot added size/xl and removed size/xl labels Aug 11, 2026
@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@stroxler stroxler left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! I think there are at least four sets of concerns we need to address before we can merge this:

  1. Design concern: the reused references index excludes library parents and several special methods. I confirmed that Sized.__len__ and a project-local __init__ override resolve to themselves. A dedicated ancestor lookup would avoid those limitations and avoid repurposing Go to Declaration for every LSP client.

  2. Parent navigation can use offsets from the wrong document snapshot.
    [lsp.rs:5420–5431](https://github.com/meta/pyrefly/blob/64a316f1f08451e4a45d257c7aec7a35884746b7/pyrefly/lib/state/lsp.rs#L5420-L5431) selects whichever memory/filesystem counterpart appears first in an unordered handle list, then retains the original byte range. With CRLF disk contents and LF editor contents, my repro navigated to the s in self instead of f in 10/20 runs. Prefer the exact module snapshot; any counterpart fallback must reconcile the range.

  3. [Routine CodeLens refreshes enqueue uncancellable workspace searches.
    [overrideCodeLens.ts:270–281](https://github.com/meta/pyrefly/blob/64a316f1f08451e4a45d257c7aec7a35884746b7/lsp/src/overrideCodeLens.ts#L270-L281) issues declaration and implementation requests for every method—even when none has overrides. A 200-method negative fixture generated 400 requests. Implementation searches traverse reverse dependencies on the shared heavy-task queue, and execute-provider commands do not propagate the lens cancellation token. Debouncing and the per-invocation worker limit don’t cancel obsolete work. Use a cancellable server-side CodeLens query, batching methods or resolving lazily.

  4. Comment-section headings suppress otherwise-working lenses.
    [overrideCodeLens.ts:83–91](https://github.com/meta/pyrefly/blob/64a316f1f08451e4a45d257c7aec7a35884746b7/lsp/src/overrideCodeLens.ts#L83-L91) descends only through class symbols. Pyrefly nests classes under String symbols for headings such as # Models ----, so the entire subtree is skipped. The mocked-provider repro changes from one override lens to none when wrapped in a section. Traverse other container nodes while preserving class context.

@github-actions

This comment has been minimized.

@stroxler stroxler left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this needs a rebase before we can merge. The update addresses the original ancestor-lookup, snapshot-pairing, and comment-section concerns. Since we need an update anyway, here are a few more concerns worth looking into:

  1. Rebase onto main and resolve the merge conflicts.

  2. Avoid eagerly querying symbols for every navigation target.
    [overrideCodeLens.ts:280–301](https://github.com/meta/pyrefly/blob/3ec319ca6271b4bcdce1e9016966da26f288a7e9/lsp/src/overrideCodeLens.ts#L280-L301) requests document symbols for every implementation just to build lens labels. A mocked-provider repro generated one batch plus 500 symbol requests, all still pending after cancellation. Return display names in the batch, or defer multi-target naming until the user opens the quick-pick.

  3. Refresh lenses when server state changes, and handle server cancellation.
    Background indexing and changes to subclass files can leave the base file’s lenses stale because they don’t trigger a refresh. Also, [overrideCodeLens.ts:255–259](https://github.com/meta/pyrefly/blob/3ec319ca6271b4bcdce1e9016966da26f288a7e9/lsp/src/overrideCodeLens.ts#L255-L259) rethrows server-initiated cancellation when the local token/version hasn’t changed, leaving lenses missing. Add server-driven invalidation and an appropriate cancellation/retry path.

  4. Validate notebook requests against the correct version.
    [server.rs:6055–6058](https://github.com/meta/pyrefly/blob/3ec319ca6271b4bcdce1e9016966da26f288a7e9/pyrefly/lib/lsp/non_wasm/server.rs#L6055-L6058) compares the cell document’s version with the notebook’s version. A backend repro succeeds initially, then rejects the unchanged cell after a metadata-only notebook update. Track cell versions or explicitly send and validate the notebook version; add that regression test.

Optional, nonblocking optimization: cache the method lookup/remapping maps instead of rebuilding them for every reverse dependency, and skip candidates with empty parent maps.

@github-actions

Copy link
Copy Markdown

According to mypy_primer, this change doesn't affect type check results on a corpus of open source code. ✅

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants