Skip to content

fix dunder all rename #4344 - #5625

Open
asukaminato0721 wants to merge 11 commits into
pyrefly-org:mainfrom
asukaminato0721:4344-dunder-all-rename
Open

asukaminato0721 wants to merge 11 commits into
pyrefly-org:mainfrom
asukaminato0721:4344-dunder-all-rename

Conversation

@asukaminato0721

@asukaminato0721 asukaminato0721 commented Nov 12, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Fixes part of #4344

support rename for __all__

The shared paired-rename test helper uses StopAtRenamedImports so local aliases keep their own identity, consistent with rename.

stack on #5588

  • I am a human, and I fully understand the code I am submitting.

Test Plan

add test

@github-actions

github-actions Bot commented Nov 12, 2026 •

Copy link
Copy Markdown

✅ This PR meets all requirements from our pull request checklist.

Optional recommendations:

  • This PR is on the larger side. If parts of it could be merged on their own, consider splitting it into separate PRs for faster review. If you've already split it as far as is practical, no action is needed.

Note: this comment updates automatically after changes to the PR. Updates may take up to half an hour.

@meta-codesync

meta-codesync Bot commented Nov 12, 2026

Copy link
Copy Markdown
Contributor

This pull request has been imported. If you are a Meta employee, you can view this in D131486069. (Because this pull request was imported automatically, there will not be any future comments.)

@github-actions

This comment has been minimized.

@kinto0 kinto0 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, rename builds on the #5588 reference bridge, keeps aliases, and only rewrites the string contents. The tests are thorough (Unicode, raw/triple-quoted strings, implicit concatenation, stdlib imports, source/stub/consumer). A few cleanups inline; these cover only the increment over #5588.

Comment thread pyrefly/lib/state/lsp.rs Outdated
}

/// Return the content range of a single string literal with the given expression range.
fn string_literal_content_range(ast: &ModModule, range: TextRange) -> Option<TextRange> {

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.

This searches the AST again for a string literal whose content range #5588 already computes (Bindings::dunder_all_entries, or DunderAllEntry if the range moves into the exports step as suggested there). Can prepare_rename read the stored content range instead, so this helper is not needed?

Comment thread pyrefly/lib/state/lsp.rs Outdated
handle,
position,
FindPreference {
import_behavior: if dunder_all_entry.is_some() {

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.

Switching import_behavior only for __all__ entries adds a special case to prepare_rename. If go-to-definition and references for __all__ entries both go through dunder_all_binding + find_export_for_key (my comment on #5588), can this use one preference for all targets?

Comment thread pyrefly/lib/state/lsp.rs
.map(Vec1::into_vec)
.unwrap_or_default();

if dunder_all_entry.is_some()

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.

This condition is hard to follow: it rejects the entry if any definition is bundled, or if a definition lands on another __all__ string. Can it be expressed directly from the binding instead? For example: reject when dunder_all_binding finds no binding, or when the resolved export is bundled. Please also add a short comment that states the invariant.

&source_handle,
TextSize::try_from(position).unwrap(),
FindPreference {
import_behavior: ImportBehavior::StopAtRenamedImports,

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.

This changes the shared replace_paired_references helper for every paired-rename test, not only the __all__ ones. Is that intended? If yes, please explain in the summary why StopAtRenamedImports is right for the existing tests too.

Use the existing definition lookup to read the exported symbol type. Keep string literal types for strings outside __all__.
Read the current checked module’s final export answer so buffers, stubs, and unopened dependencies supply the correct type.
Resolve __all__ entries only after identifier lookup fails. Cover go-to-type-definition and remove unrelated hover changes.
Resolve each entry to its definition before adding its string content range. Respect import aliases so references to independent names remain separate.
Preserve local alias identity and retain export occurrences in the normal reference index so unopened modules need no navigation queries.
Keep string content ranges from export extraction and resolve navigation and references through the checked binding. Preserve interface documentation without changing symbol identity.
Use string content ranges to preserve quotes and prefixes. Keep local source definitions during reference operations so rename updates both source files and their stubs. Validate the target before offering rename.
@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.

3 participants