Skip to content

Commit 8278f75

Browse files
[ty] Qualify inlay hint edit symbol when possibly referencing another variable (#23265)
1 parent 10c082f commit 8278f75

2 files changed

Lines changed: 113 additions & 9 deletions

File tree

crates/ty_ide/src/importer.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -363,14 +363,17 @@ impl<'ast> MembersInScope<'ast> {
363363
MembersInScope { at, map }
364364
}
365365

366-
pub(crate) fn contains_symbol(&self, symbol_name: &str) -> bool {
367-
self.map.iter().any(|(name, _)| name == symbol_name)
366+
pub(crate) fn find_member(&self, symbol_name: &str) -> Option<&MemberInScope> {
367+
self.map
368+
.iter()
369+
.find(|(name, _)| *name == symbol_name)
370+
.map(|(_, member)| member)
368371
}
369372
}
370373

371374
#[derive(Debug)]
372-
struct MemberInScope<'ast> {
373-
ty: Type<'ast>,
375+
pub(crate) struct MemberInScope<'ast> {
376+
pub(crate) ty: Type<'ast>,
374377
kind: MemberImportKind<'ast>,
375378
}
376379

crates/ty_ide/src/inlay_hints.rs

Lines changed: 106 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,8 @@ impl InlayHint {
102102
let module_name = module.name(db).as_str();
103103

104104
dynamic_importer.import_symbol(
105+
db,
106+
ty,
105107
module_name,
106108
definition_name,
107109
&details.label[start..end],
@@ -652,6 +654,8 @@ impl<'a, 'db> DynamicImporter<'a, 'db> {
652654
/// If the symbol in the text edit needs to be qualified, we return the qualified symbol text.
653655
fn import_symbol(
654656
&mut self,
657+
db: &dyn Db,
658+
ty: &Type,
655659
module_name: &str,
656660
symbol_name: &str,
657661
label_text: &str,
@@ -664,12 +668,19 @@ impl<'a, 'db> DynamicImporter<'a, 'db> {
664668
.members_in_scope_at(self.scope_node, self.scope_offset)
665669
});
666670

667-
if members.contains_symbol(symbol_name) {
668-
return None;
669-
}
670-
671671
// Check if the label is like `foo.A`
672-
let is_possibly_qualified_name = label_text.contains('.');
672+
let mut is_possibly_qualified_name = label_text.contains('.');
673+
674+
if let Some(member) = members.find_member(symbol_name) {
675+
if member.ty.definition(db) == ty.definition(db) {
676+
return None;
677+
}
678+
679+
// There is another member in scope with the same name,
680+
// so we need to qualify this so we don't reference the
681+
// in scope member.
682+
is_possibly_qualified_name = true;
683+
}
673684

674685
let key = DynamicallyImportedMember {
675686
module: module_name.to_string(),
@@ -8529,6 +8540,96 @@ mod tests {
85298540
"#);
85308541
}
85318542

8543+
/// Tests that if we have an inlay hint containing a symbol that is referenced
8544+
/// in another module, that we qualify the inlay hint symbol with the module name,
8545+
/// so we don't accidentally reference the in scope symbol.
8546+
#[test]
8547+
fn test_auto_import_symbol_in_scope_same_name() {
8548+
let mut test = inlay_hint_test(
8549+
r#"
8550+
from dataclasses import dataclass
8551+
import foo
8552+
8553+
class A: ...
8554+
8555+
@dataclass
8556+
class B[T]:
8557+
x: T
8558+
8559+
b = B(foo.A())
8560+
"#,
8561+
);
8562+
8563+
test.with_extra_file(
8564+
"foo.py",
8565+
r#"
8566+
class A: ...
8567+
"#,
8568+
);
8569+
8570+
assert_snapshot!(test.inlay_hints(), @"
8571+
8572+
from dataclasses import dataclass
8573+
import foo
8574+
8575+
class A: ...
8576+
8577+
@dataclass
8578+
class B[T]:
8579+
x: T
8580+
8581+
b[: B[A]] = B([x=]foo.A())
8582+
8583+
---------------------------------------------
8584+
info[inlay-hint-location]: Inlay Hint Target
8585+
--> main.py:8:7
8586+
|
8587+
7 | @dataclass
8588+
8 | class B[T]:
8589+
| ^
8590+
9 | x: T
8591+
|
8592+
info: Source
8593+
--> main2.py:11:5
8594+
|
8595+
9 | x: T
8596+
10 |
8597+
11 | b[: B[A]] = B([x=]foo.A())
8598+
| ^
8599+
|
8600+
8601+
info[inlay-hint-location]: Inlay Hint Target
8602+
--> foo.py:2:19
8603+
|
8604+
2 | class A: ...
8605+
| ^
8606+
|
8607+
info: Source
8608+
--> main2.py:11:7
8609+
|
8610+
9 | x: T
8611+
10 |
8612+
11 | b[: B[A]] = B([x=]foo.A())
8613+
| ^
8614+
|
8615+
8616+
---------------------------------------------
8617+
info[inlay-hint-edit]: File after edits
8618+
info: Source
8619+
8620+
from dataclasses import dataclass
8621+
import foo
8622+
8623+
class A: ...
8624+
8625+
@dataclass
8626+
class B[T]:
8627+
x: T
8628+
8629+
b: B[foo.A] = B(foo.A())
8630+
");
8631+
}
8632+
85328633
struct InlayHintLocationDiagnostic {
85338634
source: FileRange,
85348635
target: FileRange,

0 commit comments

Comments
 (0)