Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 4f5f7e2

Browse files
committed
feat: import trait with alias
1 parent 954fb1d commit 4f5f7e2

File tree

2 files changed

+77
-12
lines changed

2 files changed

+77
-12
lines changed

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

Lines changed: 43 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use ide_db::{
55
helpers::mod_path_to_ast,
66
imports::{
77
import_assets::{ImportAssets, ImportCandidate, LocatedImport},
8-
insert_use::{insert_use, ImportScope},
8+
insert_use::{insert_use, insert_use_as_alias, ImportScope},
99
},
1010
};
1111
use syntax::{ast, AstNode, NodeOrToken, SyntaxElement};
@@ -129,10 +129,12 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<
129129
for import in proposed_imports {
130130
let import_path = import.import_path;
131131

132+
let (assist_id, import_name) =
133+
(AssistId("auto_import", AssistKind::QuickFix), import_path.display(ctx.db()));
132134
acc.add_group(
133135
&group_label,
134-
AssistId("auto_import", AssistKind::QuickFix),
135-
format!("Import `{}`", import_path.display(ctx.db())),
136+
assist_id,
137+
format!("Import `{}`", import_name),
136138
range,
137139
|builder| {
138140
let scope = match scope.clone() {
@@ -143,6 +145,38 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<
143145
insert_use(&scope, mod_path_to_ast(&import_path), &ctx.config.insert_use);
144146
},
145147
);
148+
149+
match import_assets.import_candidate() {
150+
ImportCandidate::TraitAssocItem(name) | ImportCandidate::TraitMethod(name) => {
151+
let is_method =
152+
matches!(import_assets.import_candidate(), ImportCandidate::TraitMethod(_));
153+
let type_ = if is_method { "method" } else { "item" };
154+
let group_label = GroupLabel(format!(
155+
"Import a trait for {} {} by alias",
156+
type_,
157+
name.assoc_item_name.text()
158+
));
159+
acc.add_group(
160+
&group_label,
161+
assist_id,
162+
format!("Import `{} as _`", import_name),
163+
range,
164+
|builder| {
165+
let scope = match scope.clone() {
166+
ImportScope::File(it) => ImportScope::File(builder.make_mut(it)),
167+
ImportScope::Module(it) => ImportScope::Module(builder.make_mut(it)),
168+
ImportScope::Block(it) => ImportScope::Block(builder.make_mut(it)),
169+
};
170+
insert_use_as_alias(
171+
&scope,
172+
mod_path_to_ast(&import_path),
173+
&ctx.config.insert_use,
174+
);
175+
},
176+
);
177+
}
178+
_ => {}
179+
}
146180
}
147181
Some(())
148182
}
@@ -723,7 +757,7 @@ fn main() {
723757
}
724758
",
725759
r"
726-
use test_mod::TestTrait;
760+
use test_mod::TestTrait as _;
727761
728762
mod test_mod {
729763
pub trait TestTrait {
@@ -794,7 +828,7 @@ fn main() {
794828
}
795829
",
796830
r"
797-
use test_mod::TestTrait;
831+
use test_mod::TestTrait as _;
798832
799833
mod test_mod {
800834
pub trait TestTrait {
@@ -866,7 +900,7 @@ fn main() {
866900
}
867901
",
868902
r"
869-
use test_mod::TestTrait;
903+
use test_mod::TestTrait as _;
870904
871905
mod test_mod {
872906
pub trait TestTrait {
@@ -908,7 +942,7 @@ fn main() {
908942
}
909943
",
910944
r"
911-
use dep::test_mod::TestTrait;
945+
use dep::test_mod::TestTrait as _;
912946
913947
fn main() {
914948
let test_struct = dep::test_mod::TestStruct {};
@@ -939,7 +973,7 @@ fn main() {
939973
}
940974
",
941975
r"
942-
use dep::test_mod::TestTrait;
976+
use dep::test_mod::TestTrait as _;
943977
944978
fn main() {
945979
dep::test_mod::TestStruct::test_function
@@ -969,7 +1003,7 @@ fn main() {
9691003
}
9701004
",
9711005
r"
972-
use dep::test_mod::TestTrait;
1006+
use dep::test_mod::TestTrait as _;
9731007
9741008
fn main() {
9751009
dep::test_mod::TestStruct::CONST

crates/ide-db/src/imports/insert_use.rs

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use syntax::{
99
algo,
1010
ast::{
1111
self, edit_in_place::Removable, make, AstNode, HasAttrs, HasModuleItem, HasVisibility,
12-
PathSegmentKind,
12+
PathSegmentKind, Rename, UseTree,
1313
},
1414
ted, Direction, NodeOrToken, SyntaxKind, SyntaxNode,
1515
};
@@ -157,6 +157,33 @@ impl ImportScope {
157157

158158
/// Insert an import path into the given file/node. A `merge` value of none indicates that no import merging is allowed to occur.
159159
pub fn insert_use(scope: &ImportScope, path: ast::Path, cfg: &InsertUseConfig) {
160+
insert_use_with_alias_option(scope, path, cfg, None);
161+
}
162+
163+
pub fn insert_use_as_alias(scope: &ImportScope, path: ast::Path, cfg: &InsertUseConfig) {
164+
let text: &str = "use foo as _";
165+
let parse = syntax::SourceFile::parse(text);
166+
let node = match parse.tree().syntax().descendants().find_map(UseTree::cast) {
167+
Some(it) => it,
168+
None => {
169+
panic!(
170+
"Failed to make ast node `{}` from text {}",
171+
std::any::type_name::<Rename>(),
172+
text
173+
)
174+
}
175+
};
176+
let alias = node.rename();
177+
178+
insert_use_with_alias_option(scope, path, cfg, alias);
179+
}
180+
181+
fn insert_use_with_alias_option(
182+
scope: &ImportScope,
183+
path: ast::Path,
184+
cfg: &InsertUseConfig,
185+
alias: Option<ast::Rename>,
186+
) {
160187
let _p = profile::span("insert_use");
161188
let mut mb = match cfg.granularity {
162189
ImportGranularity::Crate => Some(MergeBehavior::Crate),
@@ -175,8 +202,12 @@ pub fn insert_use(scope: &ImportScope, path: ast::Path, cfg: &InsertUseConfig) {
175202
};
176203
}
177204

178-
let use_item =
179-
make::use_(None, make::use_tree(path.clone(), None, None, false)).clone_for_update();
205+
let use_item = if alias.is_some() {
206+
make::use_(None, make::use_tree(path.clone(), None, alias, false)).clone_for_update()
207+
} else {
208+
make::use_(None, make::use_tree(path.clone(), None, None, false)).clone_for_update()
209+
};
210+
180211
// merge into existing imports if possible
181212
if let Some(mb) = mb {
182213
let filter = |it: &_| !(cfg.skip_glob_imports && ast::Use::is_simple_glob(it));

0 commit comments

Comments
 (0)