Skip to content

Commit b986d8a

Browse files
committed
Complete exported macros in #[macro_use($0)]
1 parent 21b06c1 commit b986d8a

File tree

6 files changed

+123
-0
lines changed

6 files changed

+123
-0
lines changed

crates/ide-completion/src/completions/attribute.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ mod cfg;
2626
mod derive;
2727
mod lint;
2828
mod repr;
29+
mod macro_use;
2930

3031
pub(crate) use self::derive::complete_derive_path;
3132

@@ -35,6 +36,7 @@ pub(crate) fn complete_known_attribute_input(
3536
ctx: &CompletionContext<'_>,
3637
&colon_prefix: &bool,
3738
fake_attribute_under_caret: &ast::Attr,
39+
extern_crate: Option<&ast::ExternCrate>,
3840
) -> Option<()> {
3941
let attribute = fake_attribute_under_caret;
4042
let name_ref = match attribute.path() {
@@ -66,6 +68,9 @@ pub(crate) fn complete_known_attribute_input(
6668
lint::complete_lint(acc, ctx, colon_prefix, &existing_lints, &lints);
6769
}
6870
"cfg" => cfg::complete_cfg(acc, ctx),
71+
"macro_use" => {
72+
macro_use::complete_macro_use(acc, ctx, extern_crate, &parse_tt_as_comma_sep_paths(tt)?)
73+
}
6974
_ => (),
7075
}
7176
Some(())
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
use hir::ModuleDef;
2+
use ide_db::SymbolKind;
3+
use syntax::ast;
4+
5+
use crate::{context::CompletionContext, item::CompletionItem, Completions};
6+
7+
pub(super) fn complete_macro_use(
8+
acc: &mut Completions,
9+
ctx: &CompletionContext<'_>,
10+
extern_crate: Option<&ast::ExternCrate>,
11+
existing_imports: &[ast::Path],
12+
) {
13+
let Some(extern_crate) = extern_crate else { return };
14+
let Some(extern_crate) = ctx.sema.to_def(extern_crate) else { return };
15+
let Some(krate) = extern_crate.resolved_crate(ctx.db) else { return };
16+
17+
for mod_def in krate.root_module().declarations(ctx.db) {
18+
if let ModuleDef::Macro(mac) = mod_def {
19+
let mac_name = mac.name(ctx.db);
20+
let Some(mac_name) = mac_name.as_str() else { continue };
21+
22+
let existing_import = existing_imports
23+
.iter()
24+
.filter_map(|p| p.as_single_name_ref())
25+
.find(|n| n.text() == mac_name);
26+
if existing_import.is_some() {
27+
continue;
28+
}
29+
30+
let item = CompletionItem::new(SymbolKind::Macro, ctx.source_range(), mac_name);
31+
item.add_to(acc, ctx.db);
32+
}
33+
}
34+
}

crates/ide-completion/src/context.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,7 @@ pub(super) enum CompletionAnalysis {
371371
UnexpandedAttrTT {
372372
colon_prefix: bool,
373373
fake_attribute_under_caret: Option<ast::Attr>,
374+
extern_crate: Option<ast::ExternCrate>,
374375
},
375376
}
376377

crates/ide-completion/src/context/analysis.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,11 +254,13 @@ fn analyze(
254254
{
255255
let colon_prefix = previous_non_trivia_token(self_token.clone())
256256
.map_or(false, |it| T![:] == it.kind());
257+
257258
CompletionAnalysis::UnexpandedAttrTT {
258259
fake_attribute_under_caret: fake_ident_token
259260
.parent_ancestors()
260261
.find_map(ast::Attr::cast),
261262
colon_prefix,
263+
extern_crate: p.ancestors().find_map(ast::ExternCrate::cast),
262264
}
263265
} else {
264266
return None;

crates/ide-completion/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,12 +211,14 @@ pub fn completions(
211211
CompletionAnalysis::UnexpandedAttrTT {
212212
colon_prefix,
213213
fake_attribute_under_caret: Some(attr),
214+
extern_crate,
214215
} => {
215216
completions::attribute::complete_known_attribute_input(
216217
acc,
217218
ctx,
218219
colon_prefix,
219220
attr,
221+
extern_crate.as_ref(),
220222
);
221223
}
222224
CompletionAnalysis::UnexpandedAttrTT { .. } | CompletionAnalysis::String { .. } => (),

crates/ide-completion/src/tests/attribute.rs

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1067,3 +1067,82 @@ mod repr {
10671067
);
10681068
}
10691069
}
1070+
1071+
mod macro_use {
1072+
use super::*;
1073+
1074+
#[test]
1075+
fn completes_macros() {
1076+
check(
1077+
r#"
1078+
//- /dep.rs crate:dep
1079+
#[macro_export]
1080+
macro_rules! foo {
1081+
() => {};
1082+
}
1083+
1084+
#[macro_export]
1085+
macro_rules! bar {
1086+
() => {};
1087+
}
1088+
1089+
//- /main.rs crate:main deps:dep
1090+
#[macro_use($0)]
1091+
extern crate dep;
1092+
"#,
1093+
expect![[r#"
1094+
ma bar
1095+
ma foo
1096+
"#]],
1097+
)
1098+
}
1099+
1100+
#[test]
1101+
fn only_completes_exported_macros() {
1102+
check(
1103+
r#"
1104+
//- /dep.rs crate:dep
1105+
#[macro_export]
1106+
macro_rules! foo {
1107+
() => {};
1108+
}
1109+
1110+
macro_rules! bar {
1111+
() => {};
1112+
}
1113+
1114+
//- /main.rs crate:main deps:dep
1115+
#[macro_use($0)]
1116+
extern crate dep;
1117+
"#,
1118+
expect![[r#"
1119+
ma foo
1120+
"#]],
1121+
)
1122+
}
1123+
1124+
#[test]
1125+
fn does_not_completes_already_imported_macros() {
1126+
check(
1127+
r#"
1128+
//- /dep.rs crate:dep
1129+
#[macro_export]
1130+
macro_rules! foo {
1131+
() => {};
1132+
}
1133+
1134+
#[macro_export]
1135+
macro_rules! bar {
1136+
() => {};
1137+
}
1138+
1139+
//- /main.rs crate:main deps:dep
1140+
#[macro_use(foo, $0)]
1141+
extern crate dep;
1142+
"#,
1143+
expect![[r#"
1144+
ma bar
1145+
"#]],
1146+
)
1147+
}
1148+
}

0 commit comments

Comments
 (0)