Skip to content

Commit d5f77f3

Browse files
Merge #3685
3685: Auto import macros r=SomeoneToIgnore a=SomeoneToIgnore If I got it right, assists test infra does not support multiple crates snippets (https://github.com/rust-analyzer/rust-analyzer/blob/2720e2374be951bb762ff2815dd67c7ffe3419b7/crates/ra_hir_def/src/nameres/tests.rs#L491) hence no tests added for the macro import. Co-authored-by: Kirill Bulatov <mail4score@gmail.com>
2 parents f9494f1 + dd3b641 commit d5f77f3

File tree

9 files changed

+100
-37
lines changed

9 files changed

+100
-37
lines changed

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/ra_assists/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ format-buf = "1.0.0"
1212
join_to_string = "0.1.3"
1313
rustc-hash = "1.1.0"
1414
itertools = "0.9.0"
15+
either = "1.5.3"
1516

1617
ra_syntax = { path = "../ra_syntax" }
1718
ra_text_edit = { path = "../ra_text_edit" }

crates/ra_assists/src/handlers/auto_import.rs

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use crate::{
1717
utils::insert_use_statement,
1818
AssistId,
1919
};
20+
use either::Either;
2021

2122
// Assist: auto_import
2223
//
@@ -58,6 +59,7 @@ pub(crate) fn auto_import(ctx: AssistCtx) -> Option<Assist> {
5859
group.finish()
5960
}
6061

62+
#[derive(Debug)]
6163
struct AutoImportAssets {
6264
import_candidate: ImportCandidate,
6365
module_with_name_to_import: Module,
@@ -127,14 +129,14 @@ impl AutoImportAssets {
127129
ImportsLocator::new(db)
128130
.find_imports(&self.get_search_query())
129131
.into_iter()
130-
.filter_map(|module_def| match &self.import_candidate {
132+
.filter_map(|candidate| match &self.import_candidate {
131133
ImportCandidate::TraitAssocItem(assoc_item_type, _) => {
132-
let located_assoc_item = match module_def {
133-
ModuleDef::Function(located_function) => located_function
134+
let located_assoc_item = match candidate {
135+
Either::Left(ModuleDef::Function(located_function)) => located_function
134136
.as_assoc_item(db)
135137
.map(|assoc| assoc.container(db))
136138
.and_then(Self::assoc_to_trait),
137-
ModuleDef::Const(located_const) => located_const
139+
Either::Left(ModuleDef::Const(located_const)) => located_const
138140
.as_assoc_item(db)
139141
.map(|assoc| assoc.container(db))
140142
.and_then(Self::assoc_to_trait),
@@ -153,10 +155,11 @@ impl AutoImportAssets {
153155
|_, assoc| Self::assoc_to_trait(assoc.container(db)),
154156
)
155157
.map(ModuleDef::from)
158+
.map(Either::Left)
156159
}
157160
ImportCandidate::TraitMethod(function_callee, _) => {
158161
let located_assoc_item =
159-
if let ModuleDef::Function(located_function) = module_def {
162+
if let Either::Left(ModuleDef::Function(located_function)) = candidate {
160163
located_function
161164
.as_assoc_item(db)
162165
.map(|assoc| assoc.container(db))
@@ -179,10 +182,18 @@ impl AutoImportAssets {
179182
},
180183
)
181184
.map(ModuleDef::from)
185+
.map(Either::Left)
186+
}
187+
_ => Some(candidate),
188+
})
189+
.filter_map(|candidate| match candidate {
190+
Either::Left(module_def) => {
191+
self.module_with_name_to_import.find_use_path(db, module_def)
192+
}
193+
Either::Right(macro_def) => {
194+
self.module_with_name_to_import.find_use_path(db, macro_def)
182195
}
183-
_ => Some(module_def),
184196
})
185-
.filter_map(|module_def| self.module_with_name_to_import.find_use_path(db, module_def))
186197
.filter(|use_path| !use_path.segments.is_empty())
187198
.take(20)
188199
.collect::<BTreeSet<_>>()
@@ -439,6 +450,30 @@ mod tests {
439450
);
440451
}
441452

453+
#[test]
454+
fn macro_import() {
455+
check_assist(
456+
auto_import,
457+
r"
458+
//- /lib.rs crate:crate_with_macro
459+
#[macro_export]
460+
macro_rules! foo {
461+
() => ()
462+
}
463+
464+
//- /main.rs crate:main deps:crate_with_macro
465+
fn main() {
466+
foo<|>
467+
}",
468+
r"use crate_with_macro::foo;
469+
470+
fn main() {
471+
foo<|>
472+
}
473+
",
474+
);
475+
}
476+
442477
#[test]
443478
fn auto_import_target() {
444479
check_assist_target(

crates/ra_assists/src/handlers/fill_match_arms.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
use std::iter;
44

5-
use hir::{Adt, HasSource, Semantics};
5+
use hir::{Adt, HasSource, ModuleDef, Semantics};
66
use itertools::Itertools;
77
use ra_ide_db::RootDatabase;
88

@@ -154,7 +154,7 @@ fn resolve_tuple_of_enum_def(
154154
}
155155

156156
fn build_pat(db: &RootDatabase, module: hir::Module, var: hir::EnumVariant) -> Option<ast::Pat> {
157-
let path = crate::ast_transform::path_to_ast(module.find_use_path(db, var.into())?);
157+
let path = crate::ast_transform::path_to_ast(module.find_use_path(db, ModuleDef::from(var))?);
158158

159159
// FIXME: use HIR for this; it doesn't currently expose struct vs. tuple vs. unit variants though
160160
let pat: ast::Pat = match var.source(db).value.kind() {

crates/ra_assists/src/lib.rs

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,6 @@ mod helpers {
165165

166166
use ra_db::{fixture::WithFixture, FileId, FileRange, SourceDatabaseExt};
167167
use ra_ide_db::{symbol_index::SymbolsDatabase, RootDatabase};
168-
use ra_syntax::TextRange;
169168
use test_utils::{add_cursor, assert_eq_text, extract_range_or_offset, RangeOrOffset};
170169

171170
use crate::{AssistCtx, AssistHandler};
@@ -175,8 +174,7 @@ mod helpers {
175174
let (mut db, file_id) = RootDatabase::with_single_file(text);
176175
// FIXME: ideally, this should be done by the above `RootDatabase::with_single_file`,
177176
// but it looks like this might need specialization? :(
178-
let local_roots = vec![db.file_source_root(file_id)];
179-
db.set_local_roots(Arc::new(local_roots));
177+
db.set_local_roots(Arc::new(vec![db.file_source_root(file_id)]));
180178
(db, file_id)
181179
}
182180

@@ -206,19 +204,32 @@ mod helpers {
206204
}
207205

208206
fn check(assist: AssistHandler, before: &str, expected: ExpectedResult) {
209-
let (range_or_offset, before) = extract_range_or_offset(before);
210-
let range: TextRange = range_or_offset.into();
207+
let (text_without_caret, file_with_caret_id, range_or_offset, db) =
208+
if before.contains("//-") {
209+
let (mut db, position) = RootDatabase::with_position(before);
210+
db.set_local_roots(Arc::new(vec![db.file_source_root(position.file_id)]));
211+
(
212+
db.file_text(position.file_id).as_ref().to_owned(),
213+
position.file_id,
214+
RangeOrOffset::Offset(position.offset),
215+
db,
216+
)
217+
} else {
218+
let (range_or_offset, text_without_caret) = extract_range_or_offset(before);
219+
let (db, file_id) = with_single_file(&text_without_caret);
220+
(text_without_caret, file_id, range_or_offset, db)
221+
};
222+
223+
let frange = FileRange { file_id: file_with_caret_id, range: range_or_offset.into() };
211224

212-
let (db, file_id) = with_single_file(&before);
213-
let frange = FileRange { file_id, range };
214225
let sema = Semantics::new(&db);
215226
let assist_ctx = AssistCtx::new(&sema, frange, true);
216227

217228
match (assist(assist_ctx), expected) {
218229
(Some(assist), ExpectedResult::After(after)) => {
219230
let action = assist.0[0].action.clone().unwrap();
220231

221-
let mut actual = action.edit.apply(&before);
232+
let mut actual = action.edit.apply(&text_without_caret);
222233
match action.cursor_position {
223234
None => {
224235
if let RangeOrOffset::Offset(before_cursor_pos) = range_or_offset {
@@ -237,7 +248,7 @@ mod helpers {
237248
(Some(assist), ExpectedResult::Target(target)) => {
238249
let action = assist.0[0].action.clone().unwrap();
239250
let range = action.target.expect("expected target on action");
240-
assert_eq_text!(&before[range], target);
251+
assert_eq_text!(&text_without_caret[range], target);
241252
}
242253
(Some(_), ExpectedResult::NotApplicable) => panic!("assist should not be applicable!"),
243254
(None, ExpectedResult::After(_)) | (None, ExpectedResult::Target(_)) => {

crates/ra_hir/src/code_model.rs

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,11 @@ use ra_syntax::{
3333
};
3434
use rustc_hash::FxHashSet;
3535

36-
use crate::{db::HirDatabase, has_source::HasSource, CallableDef, HirDisplay, InFile, Name};
36+
use crate::{
37+
db::{DefDatabase, HirDatabase},
38+
has_source::HasSource,
39+
CallableDef, HirDisplay, InFile, Name,
40+
};
3741

3842
/// hir::Crate describes a single crate. It's the main interface with which
3943
/// a crate's dependencies interact. Mostly, it should be just a proxy for the
@@ -274,20 +278,10 @@ impl Module {
274278
/// this module, if possible.
275279
pub fn find_use_path(
276280
self,
277-
db: &dyn HirDatabase,
278-
item: ModuleDef,
281+
db: &dyn DefDatabase,
282+
item: impl Into<ItemInNs>,
279283
) -> Option<hir_def::path::ModPath> {
280-
// FIXME expose namespace choice
281-
hir_def::find_path::find_path(db.upcast(), determine_item_namespace(item), self.into())
282-
}
283-
}
284-
285-
fn determine_item_namespace(module_def: ModuleDef) -> ItemInNs {
286-
match module_def {
287-
ModuleDef::Static(_) | ModuleDef::Const(_) | ModuleDef::Function(_) => {
288-
ItemInNs::Values(module_def.into())
289-
}
290-
_ => ItemInNs::Types(module_def.into()),
284+
hir_def::find_path::find_path(db, item.into(), self.into())
291285
}
292286
}
293287

crates/ra_hir/src/from_id.rs

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ use hir_def::{
99
};
1010

1111
use crate::{
12-
Adt, AssocItem, AttrDef, DefWithBody, EnumVariant, GenericDef, Local, ModuleDef, StructField,
13-
VariantDef,
12+
code_model::ItemInNs, Adt, AssocItem, AttrDef, DefWithBody, EnumVariant, GenericDef, Local,
13+
MacroDef, ModuleDef, StructField, VariantDef,
1414
};
1515

1616
macro_rules! from_id {
@@ -228,3 +228,20 @@ impl From<(DefWithBodyId, PatId)> for Local {
228228
Local { parent, pat_id }
229229
}
230230
}
231+
232+
impl From<MacroDef> for ItemInNs {
233+
fn from(macro_def: MacroDef) -> Self {
234+
ItemInNs::Macros(macro_def.into())
235+
}
236+
}
237+
238+
impl From<ModuleDef> for ItemInNs {
239+
fn from(module_def: ModuleDef) -> Self {
240+
match module_def {
241+
ModuleDef::Static(_) | ModuleDef::Const(_) | ModuleDef::Function(_) => {
242+
ItemInNs::Values(module_def.into())
243+
}
244+
_ => ItemInNs::Types(module_def.into()),
245+
}
246+
}
247+
}

crates/ra_ide_db/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ fst = { version = "0.4", default-features = false }
1717
rustc-hash = "1.1.0"
1818
superslice = "1.0.0"
1919
once_cell = "1.3.1"
20+
either = "1.5.3"
2021

2122
ra_syntax = { path = "../ra_syntax" }
2223
ra_text_edit = { path = "../ra_text_edit" }

crates/ra_ide_db/src/imports_locator.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! This module contains an import search funcionality that is provided to the ra_assists module.
22
//! Later, this should be moved away to a separate crate that is accessible from the ra_assists module.
33
4-
use hir::{ModuleDef, Semantics};
4+
use hir::{MacroDef, ModuleDef, Semantics};
55
use ra_prof::profile;
66
use ra_syntax::{ast, AstNode, SyntaxKind::NAME};
77

@@ -10,6 +10,7 @@ use crate::{
1010
symbol_index::{self, FileSymbol, Query},
1111
RootDatabase,
1212
};
13+
use either::Either;
1314

1415
pub struct ImportsLocator<'a> {
1516
sema: Semantics<'a, RootDatabase>,
@@ -20,7 +21,7 @@ impl<'a> ImportsLocator<'a> {
2021
Self { sema: Semantics::new(db) }
2122
}
2223

23-
pub fn find_imports(&mut self, name_to_import: &str) -> Vec<ModuleDef> {
24+
pub fn find_imports(&mut self, name_to_import: &str) -> Vec<Either<ModuleDef, MacroDef>> {
2425
let _p = profile("search_for_imports");
2526
let db = self.sema.db;
2627

@@ -43,7 +44,8 @@ impl<'a> ImportsLocator<'a> {
4344
.chain(lib_results.into_iter())
4445
.filter_map(|import_candidate| self.get_name_definition(&import_candidate))
4546
.filter_map(|name_definition_to_import| match name_definition_to_import {
46-
Definition::ModuleDef(module_def) => Some(module_def),
47+
Definition::ModuleDef(module_def) => Some(Either::Left(module_def)),
48+
Definition::Macro(macro_def) => Some(Either::Right(macro_def)),
4749
_ => None,
4850
})
4951
.collect()

0 commit comments

Comments
 (0)