Skip to content

Commit 8c1c689

Browse files
Only import the item in "Unqualify method call" if needed
1 parent b2a58b8 commit 8c1c689

File tree

2 files changed

+122
-1
lines changed

2 files changed

+122
-1
lines changed

crates/hir/src/semantics.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2247,6 +2247,11 @@ impl<'db> SemanticsScope<'db> {
22472247
}
22482248
}
22492249

2250+
/// Checks if a trait is in scope, either because of an import or because we're in an impl of it.
2251+
pub fn can_use_trait_methods(&self, t: Trait) -> bool {
2252+
self.resolver.traits_in_scope(self.db).contains(&t.id)
2253+
}
2254+
22502255
/// Resolve a path as-if it was written at the given scope. This is
22512256
/// necessary a heuristic, as it doesn't take hygiene into account.
22522257
pub fn speculative_resolve(&self, ast_path: &ast::Path) -> Option<PathResolution> {

crates/ide-assists/src/handlers/unqualify_method_call.rs

Lines changed: 117 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use hir::AsAssocItem;
12
use syntax::{
23
TextRange,
34
ast::{self, AstNode, HasArgList, prec::ExprPrecedence},
@@ -43,6 +44,7 @@ pub(crate) fn unqualify_method_call(acc: &mut Assists, ctx: &AssistContext<'_>)
4344
let qualifier = path.qualifier()?;
4445
let method_name = path.segment()?.name_ref()?;
4546

47+
let scope = ctx.sema.scope(path.syntax())?;
4648
let res = ctx.sema.resolve_path(&path)?;
4749
let hir::PathResolution::Def(hir::ModuleDef::Function(fun)) = res else { return None };
4850
if !fun.has_self_param(ctx.sema.db) {
@@ -78,7 +80,14 @@ pub(crate) fn unqualify_method_call(acc: &mut Assists, ctx: &AssistContext<'_>)
7880
edit.insert(close, ")");
7981
}
8082
edit.replace(replace_comma, format!(".{method_name}("));
81-
add_import(qualifier, ctx, edit);
83+
84+
if let Some(fun) = fun.as_assoc_item(ctx.db())
85+
&& let Some(trait_) = fun.container_or_implemented_trait(ctx.db())
86+
&& !scope.can_use_trait_methods(trait_)
87+
{
88+
// Only add an import for trait methods that are not already imported.
89+
add_import(qualifier, ctx, edit);
90+
}
8291
},
8392
)
8493
}
@@ -235,4 +244,111 @@ impl S { fn assoc(S: S, S: S) {} }
235244
fn f() { S::assoc$0(S, S); }"#,
236245
);
237246
}
247+
248+
#[test]
249+
fn inherent_method() {
250+
check_assist(
251+
unqualify_method_call,
252+
r#"
253+
mod foo {
254+
pub struct Bar;
255+
impl Bar {
256+
pub fn bar(self) {}
257+
}
258+
}
259+
260+
fn baz() {
261+
foo::Bar::b$0ar(foo::Bar);
262+
}
263+
"#,
264+
r#"
265+
mod foo {
266+
pub struct Bar;
267+
impl Bar {
268+
pub fn bar(self) {}
269+
}
270+
}
271+
272+
fn baz() {
273+
foo::Bar.bar();
274+
}
275+
"#,
276+
);
277+
}
278+
279+
#[test]
280+
fn trait_method_in_impl() {
281+
check_assist(
282+
unqualify_method_call,
283+
r#"
284+
mod foo {
285+
pub trait Bar {
286+
pub fn bar(self) {}
287+
}
288+
}
289+
290+
struct Baz;
291+
impl foo::Bar for Baz {
292+
fn bar(self) {
293+
foo::Bar::b$0ar(Baz);
294+
}
295+
}
296+
"#,
297+
r#"
298+
mod foo {
299+
pub trait Bar {
300+
pub fn bar(self) {}
301+
}
302+
}
303+
304+
struct Baz;
305+
impl foo::Bar for Baz {
306+
fn bar(self) {
307+
Baz.bar();
308+
}
309+
}
310+
"#,
311+
);
312+
}
313+
314+
#[test]
315+
fn trait_method_already_imported() {
316+
check_assist(
317+
unqualify_method_call,
318+
r#"
319+
mod foo {
320+
pub struct Foo;
321+
pub trait Bar {
322+
pub fn bar(self) {}
323+
}
324+
impl Bar for Foo {
325+
pub fn bar(self) {}
326+
}
327+
}
328+
329+
use foo::Bar;
330+
331+
fn baz() {
332+
foo::Bar::b$0ar(foo::Foo);
333+
}
334+
"#,
335+
r#"
336+
mod foo {
337+
pub struct Foo;
338+
pub trait Bar {
339+
pub fn bar(self) {}
340+
}
341+
impl Bar for Foo {
342+
pub fn bar(self) {}
343+
}
344+
}
345+
346+
use foo::Bar;
347+
348+
fn baz() {
349+
foo::Foo.bar();
350+
}
351+
"#,
352+
);
353+
}
238354
}

0 commit comments

Comments
 (0)