Skip to content

Commit 6a48a94

Browse files
Merge #4268
4268: Support auto-import in macro r=SomeoneToIgnore a=edwin0cheng Fixed: #3854 Co-authored-by: Edwin Cheng <[email protected]>
2 parents baa35b0 + 2034002 commit 6a48a94

File tree

5 files changed

+66
-19
lines changed

5 files changed

+66
-19
lines changed

crates/ra_assists/src/assist_ctx.rs

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ impl<'a> AssistCtx<'a> {
105105
let mut info = AssistInfo::new(label);
106106
if self.should_compute_edit {
107107
let action = {
108-
let mut edit = ActionBuilder::default();
108+
let mut edit = ActionBuilder::new(&self);
109109
f(&mut edit);
110110
edit.build()
111111
};
@@ -130,6 +130,12 @@ impl<'a> AssistCtx<'a> {
130130
pub(crate) fn find_node_at_offset<N: AstNode>(&self) -> Option<N> {
131131
find_node_at_offset(self.source_file.syntax(), self.frange.range.start())
132132
}
133+
134+
pub(crate) fn find_node_at_offset_with_descend<N: AstNode>(&self) -> Option<N> {
135+
self.sema
136+
.find_node_at_offset_with_descend(self.source_file.syntax(), self.frange.range.start())
137+
}
138+
133139
pub(crate) fn covering_element(&self) -> SyntaxElement {
134140
find_covering_element(self.source_file.syntax(), self.frange.range)
135141
}
@@ -156,7 +162,7 @@ impl<'a> AssistGroup<'a> {
156162
let mut info = AssistInfo::new(label).with_group(GroupLabel(self.group_name.clone()));
157163
if self.ctx.should_compute_edit {
158164
let action = {
159-
let mut edit = ActionBuilder::default();
165+
let mut edit = ActionBuilder::new(&self.ctx);
160166
f(&mut edit);
161167
edit.build()
162168
};
@@ -175,15 +181,29 @@ impl<'a> AssistGroup<'a> {
175181
}
176182
}
177183

178-
#[derive(Default)]
179-
pub(crate) struct ActionBuilder {
184+
pub(crate) struct ActionBuilder<'a, 'b> {
180185
edit: TextEditBuilder,
181186
cursor_position: Option<TextSize>,
182187
target: Option<TextRange>,
183188
file: AssistFile,
189+
ctx: &'a AssistCtx<'b>,
184190
}
185191

186-
impl ActionBuilder {
192+
impl<'a, 'b> ActionBuilder<'a, 'b> {
193+
fn new(ctx: &'a AssistCtx<'b>) -> Self {
194+
Self {
195+
edit: TextEditBuilder::default(),
196+
cursor_position: None,
197+
target: None,
198+
file: AssistFile::default(),
199+
ctx,
200+
}
201+
}
202+
203+
pub(crate) fn ctx(&self) -> &AssistCtx<'b> {
204+
&self.ctx
205+
}
206+
187207
/// Replaces specified `range` of text with a given string.
188208
pub(crate) fn replace(&mut self, range: TextRange, replace_with: impl Into<String>) {
189209
self.edit.replace(range, replace_with.into())

crates/ra_assists/src/handlers/auto_import.rs

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -45,15 +45,12 @@ pub(crate) fn auto_import(ctx: AssistCtx) -> Option<Assist> {
4545
return None;
4646
}
4747

48+
let range = ctx.sema.original_range(&auto_import_assets.syntax_under_caret).range;
4849
let mut group = ctx.add_assist_group(auto_import_assets.get_import_group_message());
4950
for import in proposed_imports {
5051
group.add_assist(AssistId("auto_import"), format!("Import `{}`", &import), |edit| {
51-
edit.target(auto_import_assets.syntax_under_caret.text_range());
52-
insert_use_statement(
53-
&auto_import_assets.syntax_under_caret,
54-
&import,
55-
edit.text_edit_builder(),
56-
);
52+
edit.target(range);
53+
insert_use_statement(&auto_import_assets.syntax_under_caret, &import, edit);
5754
});
5855
}
5956
group.finish()
@@ -68,10 +65,10 @@ struct AutoImportAssets {
6865

6966
impl AutoImportAssets {
7067
fn new(ctx: &AssistCtx) -> Option<Self> {
71-
if let Some(path_under_caret) = ctx.find_node_at_offset::<ast::Path>() {
68+
if let Some(path_under_caret) = ctx.find_node_at_offset_with_descend::<ast::Path>() {
7269
Self::for_regular_path(path_under_caret, &ctx)
7370
} else {
74-
Self::for_method_call(ctx.find_node_at_offset()?, &ctx)
71+
Self::for_method_call(ctx.find_node_at_offset_with_descend()?, &ctx)
7572
}
7673
}
7774

@@ -305,6 +302,35 @@ mod tests {
305302
);
306303
}
307304

305+
#[test]
306+
fn applicable_when_found_an_import_in_macros() {
307+
check_assist(
308+
auto_import,
309+
r"
310+
macro_rules! foo {
311+
($i:ident) => { fn foo(a: $i) {} }
312+
}
313+
foo!(Pub<|>Struct);
314+
315+
pub mod PubMod {
316+
pub struct PubStruct;
317+
}
318+
",
319+
r"
320+
use PubMod::PubStruct;
321+
322+
macro_rules! foo {
323+
($i:ident) => { fn foo(a: $i) {} }
324+
}
325+
foo!(Pub<|>Struct);
326+
327+
pub mod PubMod {
328+
pub struct PubStruct;
329+
}
330+
",
331+
);
332+
}
333+
308334
#[test]
309335
fn auto_imports_are_merged() {
310336
check_assist(

crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ pub(crate) fn replace_qualified_name_with_use(ctx: AssistCtx) -> Option<Assist>
3838
"Replace qualified path with use",
3939
|edit| {
4040
let path_to_import = hir_path.mod_path().clone();
41-
insert_use_statement(path.syntax(), &path_to_import, edit.text_edit_builder());
41+
insert_use_statement(path.syntax(), &path_to_import, edit);
4242

4343
if let Some(last) = path.segment() {
4444
// Here we are assuming the assist will provide a correct use statement

crates/ra_assists/src/utils.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use ra_syntax::{
1111
};
1212
use rustc_hash::FxHashSet;
1313

14-
pub use insert_use::insert_use_statement;
14+
pub(crate) use insert_use::insert_use_statement;
1515

1616
pub fn get_missing_impl_items(
1717
sema: &Semantics<RootDatabase>,

crates/ra_assists/src/utils/insert_use.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// FIXME: rewrite according to the plan, outlined in
33
// https://github.com/rust-analyzer/rust-analyzer/issues/3301#issuecomment-592931553
44

5+
use crate::assist_ctx::ActionBuilder;
56
use hir::{self, ModPath};
67
use ra_syntax::{
78
ast::{self, NameOwner},
@@ -14,14 +15,14 @@ use ra_text_edit::TextEditBuilder;
1415
/// Creates and inserts a use statement for the given path to import.
1516
/// The use statement is inserted in the scope most appropriate to the
1617
/// the cursor position given, additionally merged with the existing use imports.
17-
pub fn insert_use_statement(
18+
pub(crate) fn insert_use_statement(
1819
// Ideally the position of the cursor, used to
1920
position: &SyntaxNode,
2021
path_to_import: &ModPath,
21-
edit: &mut TextEditBuilder,
22+
edit: &mut ActionBuilder,
2223
) {
2324
let target = path_to_import.to_string().split("::").map(SmolStr::new).collect::<Vec<_>>();
24-
let container = position.ancestors().find_map(|n| {
25+
let container = edit.ctx().sema.ancestors_with_macros(position.clone()).find_map(|n| {
2526
if let Some(module) = ast::Module::cast(n.clone()) {
2627
return module.item_list().map(|it| it.syntax().clone());
2728
}
@@ -30,7 +31,7 @@ pub fn insert_use_statement(
3031

3132
if let Some(container) = container {
3233
let action = best_action_for_target(container, position.clone(), &target);
33-
make_assist(&action, &target, edit);
34+
make_assist(&action, &target, edit.text_edit_builder());
3435
}
3536
}
3637

0 commit comments

Comments
 (0)