Complete exported macros in #[macro_use($0)]

This commit is contained in:
unexge 2023-12-16 16:19:58 +00:00
parent 21b06c1beb
commit b986d8ac92
6 changed files with 123 additions and 0 deletions

View File

@ -26,6 +26,7 @@ mod cfg;
mod derive; mod derive;
mod lint; mod lint;
mod repr; mod repr;
mod macro_use;
pub(crate) use self::derive::complete_derive_path; pub(crate) use self::derive::complete_derive_path;
@ -35,6 +36,7 @@ pub(crate) fn complete_known_attribute_input(
ctx: &CompletionContext<'_>, ctx: &CompletionContext<'_>,
&colon_prefix: &bool, &colon_prefix: &bool,
fake_attribute_under_caret: &ast::Attr, fake_attribute_under_caret: &ast::Attr,
extern_crate: Option<&ast::ExternCrate>,
) -> Option<()> { ) -> Option<()> {
let attribute = fake_attribute_under_caret; let attribute = fake_attribute_under_caret;
let name_ref = match attribute.path() { let name_ref = match attribute.path() {
@ -66,6 +68,9 @@ pub(crate) fn complete_known_attribute_input(
lint::complete_lint(acc, ctx, colon_prefix, &existing_lints, &lints); lint::complete_lint(acc, ctx, colon_prefix, &existing_lints, &lints);
} }
"cfg" => cfg::complete_cfg(acc, ctx), "cfg" => cfg::complete_cfg(acc, ctx),
"macro_use" => {
macro_use::complete_macro_use(acc, ctx, extern_crate, &parse_tt_as_comma_sep_paths(tt)?)
}
_ => (), _ => (),
} }
Some(()) Some(())

View File

@ -0,0 +1,34 @@
use hir::ModuleDef;
use ide_db::SymbolKind;
use syntax::ast;
use crate::{context::CompletionContext, item::CompletionItem, Completions};
pub(super) fn complete_macro_use(
acc: &mut Completions,
ctx: &CompletionContext<'_>,
extern_crate: Option<&ast::ExternCrate>,
existing_imports: &[ast::Path],
) {
let Some(extern_crate) = extern_crate else { return };
let Some(extern_crate) = ctx.sema.to_def(extern_crate) else { return };
let Some(krate) = extern_crate.resolved_crate(ctx.db) else { return };
for mod_def in krate.root_module().declarations(ctx.db) {
if let ModuleDef::Macro(mac) = mod_def {
let mac_name = mac.name(ctx.db);
let Some(mac_name) = mac_name.as_str() else { continue };
let existing_import = existing_imports
.iter()
.filter_map(|p| p.as_single_name_ref())
.find(|n| n.text() == mac_name);
if existing_import.is_some() {
continue;
}
let item = CompletionItem::new(SymbolKind::Macro, ctx.source_range(), mac_name);
item.add_to(acc, ctx.db);
}
}
}

View File

@ -371,6 +371,7 @@ pub(super) enum CompletionAnalysis {
UnexpandedAttrTT { UnexpandedAttrTT {
colon_prefix: bool, colon_prefix: bool,
fake_attribute_under_caret: Option<ast::Attr>, fake_attribute_under_caret: Option<ast::Attr>,
extern_crate: Option<ast::ExternCrate>,
}, },
} }

View File

@ -254,11 +254,13 @@ fn analyze(
{ {
let colon_prefix = previous_non_trivia_token(self_token.clone()) let colon_prefix = previous_non_trivia_token(self_token.clone())
.map_or(false, |it| T![:] == it.kind()); .map_or(false, |it| T![:] == it.kind());
CompletionAnalysis::UnexpandedAttrTT { CompletionAnalysis::UnexpandedAttrTT {
fake_attribute_under_caret: fake_ident_token fake_attribute_under_caret: fake_ident_token
.parent_ancestors() .parent_ancestors()
.find_map(ast::Attr::cast), .find_map(ast::Attr::cast),
colon_prefix, colon_prefix,
extern_crate: p.ancestors().find_map(ast::ExternCrate::cast),
} }
} else { } else {
return None; return None;

View File

@ -211,12 +211,14 @@ pub fn completions(
CompletionAnalysis::UnexpandedAttrTT { CompletionAnalysis::UnexpandedAttrTT {
colon_prefix, colon_prefix,
fake_attribute_under_caret: Some(attr), fake_attribute_under_caret: Some(attr),
extern_crate,
} => { } => {
completions::attribute::complete_known_attribute_input( completions::attribute::complete_known_attribute_input(
acc, acc,
ctx, ctx,
colon_prefix, colon_prefix,
attr, attr,
extern_crate.as_ref(),
); );
} }
CompletionAnalysis::UnexpandedAttrTT { .. } | CompletionAnalysis::String { .. } => (), CompletionAnalysis::UnexpandedAttrTT { .. } | CompletionAnalysis::String { .. } => (),

View File

@ -1067,3 +1067,82 @@ mod repr {
); );
} }
} }
mod macro_use {
use super::*;
#[test]
fn completes_macros() {
check(
r#"
//- /dep.rs crate:dep
#[macro_export]
macro_rules! foo {
() => {};
}
#[macro_export]
macro_rules! bar {
() => {};
}
//- /main.rs crate:main deps:dep
#[macro_use($0)]
extern crate dep;
"#,
expect![[r#"
ma bar
ma foo
"#]],
)
}
#[test]
fn only_completes_exported_macros() {
check(
r#"
//- /dep.rs crate:dep
#[macro_export]
macro_rules! foo {
() => {};
}
macro_rules! bar {
() => {};
}
//- /main.rs crate:main deps:dep
#[macro_use($0)]
extern crate dep;
"#,
expect![[r#"
ma foo
"#]],
)
}
#[test]
fn does_not_completes_already_imported_macros() {
check(
r#"
//- /dep.rs crate:dep
#[macro_export]
macro_rules! foo {
() => {};
}
#[macro_export]
macro_rules! bar {
() => {};
}
//- /main.rs crate:main deps:dep
#[macro_use(foo, $0)]
extern crate dep;
"#,
expect![[r#"
ma bar
"#]],
)
}
}