mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-28 05:53:45 +00:00
Support completion for macros
This commit is contained in:
parent
e2ebb467bd
commit
7de9537ccc
4 changed files with 295 additions and 2 deletions
|
@ -584,6 +584,42 @@ mod tests {
|
|||
kind: Function,
|
||||
detail: "fn foo()",
|
||||
},
|
||||
]"###
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn completes_quantified_macros() {
|
||||
assert_debug_snapshot!(
|
||||
do_reference_completion(
|
||||
"
|
||||
#[macro_export]
|
||||
macro_rules! foo {
|
||||
() => {}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let _ = crate::<|>
|
||||
}
|
||||
"
|
||||
),
|
||||
@r###"[
|
||||
CompletionItem {
|
||||
label: "foo",
|
||||
source_range: [179; 179),
|
||||
delete: [179; 179),
|
||||
insert: "foo!",
|
||||
kind: Macro,
|
||||
detail: "#[macro_export]\nmacro_rules! foo",
|
||||
},
|
||||
CompletionItem {
|
||||
label: "main",
|
||||
source_range: [179; 179),
|
||||
delete: [179; 179),
|
||||
insert: "main()$0",
|
||||
kind: Function,
|
||||
detail: "fn main()",
|
||||
},
|
||||
]"###
|
||||
);
|
||||
}
|
||||
|
|
|
@ -6,6 +6,15 @@ use rustc_hash::FxHashMap;
|
|||
use crate::completion::{CompletionContext, CompletionItem, CompletionKind, Completions};
|
||||
|
||||
pub(super) fn complete_scope(acc: &mut Completions, ctx: &CompletionContext) {
|
||||
// Show only macros in top level.
|
||||
if ctx.is_new_item {
|
||||
for (name, res) in ctx.analyzer.all_names(ctx.db) {
|
||||
if res.get_macros().is_some() {
|
||||
acc.add_resolution(ctx, name.to_string(), &res.only_macros());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !ctx.is_trivial_path {
|
||||
return;
|
||||
}
|
||||
|
@ -532,4 +541,224 @@ mod tests {
|
|||
]"#
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn completes_macros_as_value() {
|
||||
assert_debug_snapshot!(
|
||||
do_reference_completion(
|
||||
"
|
||||
//- /main.rs
|
||||
macro_rules! foo {
|
||||
() => {}
|
||||
}
|
||||
|
||||
#[macro_use]
|
||||
mod m1 {
|
||||
macro_rules! bar {
|
||||
() => {}
|
||||
}
|
||||
}
|
||||
|
||||
mod m2 {
|
||||
macro_rules! nope {
|
||||
() => {}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! baz {
|
||||
() => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let v = <|>
|
||||
}
|
||||
"
|
||||
),
|
||||
@r##"[
|
||||
CompletionItem {
|
||||
label: "bar",
|
||||
source_range: [252; 252),
|
||||
delete: [252; 252),
|
||||
insert: "bar!",
|
||||
kind: Macro,
|
||||
detail: "macro_rules! bar",
|
||||
},
|
||||
CompletionItem {
|
||||
label: "baz",
|
||||
source_range: [252; 252),
|
||||
delete: [252; 252),
|
||||
insert: "baz!",
|
||||
kind: Macro,
|
||||
detail: "#[macro_export]\nmacro_rules! baz",
|
||||
},
|
||||
CompletionItem {
|
||||
label: "foo",
|
||||
source_range: [252; 252),
|
||||
delete: [252; 252),
|
||||
insert: "foo!",
|
||||
kind: Macro,
|
||||
detail: "macro_rules! foo",
|
||||
},
|
||||
CompletionItem {
|
||||
label: "m1",
|
||||
source_range: [252; 252),
|
||||
delete: [252; 252),
|
||||
insert: "m1",
|
||||
kind: Module,
|
||||
},
|
||||
CompletionItem {
|
||||
label: "m2",
|
||||
source_range: [252; 252),
|
||||
delete: [252; 252),
|
||||
insert: "m2",
|
||||
kind: Module,
|
||||
},
|
||||
CompletionItem {
|
||||
label: "main",
|
||||
source_range: [252; 252),
|
||||
delete: [252; 252),
|
||||
insert: "main()$0",
|
||||
kind: Function,
|
||||
detail: "fn main()",
|
||||
},
|
||||
]"##
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn completes_both_macro_and_value() {
|
||||
assert_debug_snapshot!(
|
||||
do_reference_completion(
|
||||
"
|
||||
//- /main.rs
|
||||
macro_rules! foo {
|
||||
() => {}
|
||||
}
|
||||
|
||||
fn foo() {
|
||||
<|>
|
||||
}
|
||||
"
|
||||
),
|
||||
@r##"[
|
||||
CompletionItem {
|
||||
label: "foo",
|
||||
source_range: [49; 49),
|
||||
delete: [49; 49),
|
||||
insert: "foo!",
|
||||
kind: Macro,
|
||||
detail: "macro_rules! foo",
|
||||
},
|
||||
CompletionItem {
|
||||
label: "foo",
|
||||
source_range: [49; 49),
|
||||
delete: [49; 49),
|
||||
insert: "foo()$0",
|
||||
kind: Function,
|
||||
detail: "fn foo()",
|
||||
},
|
||||
]"##
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn completes_macros_as_type() {
|
||||
assert_debug_snapshot!(
|
||||
do_reference_completion(
|
||||
"
|
||||
//- /main.rs
|
||||
macro_rules! foo {
|
||||
() => {}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x: <|>
|
||||
}
|
||||
"
|
||||
),
|
||||
@r##"[
|
||||
CompletionItem {
|
||||
label: "foo",
|
||||
source_range: [57; 57),
|
||||
delete: [57; 57),
|
||||
insert: "foo!",
|
||||
kind: Macro,
|
||||
detail: "macro_rules! foo",
|
||||
},
|
||||
CompletionItem {
|
||||
label: "main",
|
||||
source_range: [57; 57),
|
||||
delete: [57; 57),
|
||||
insert: "main()$0",
|
||||
kind: Function,
|
||||
detail: "fn main()",
|
||||
},
|
||||
]"##
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn completes_macros_as_stmt() {
|
||||
assert_debug_snapshot!(
|
||||
do_reference_completion(
|
||||
"
|
||||
//- /main.rs
|
||||
macro_rules! foo {
|
||||
() => {}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
<|>
|
||||
}
|
||||
"
|
||||
),
|
||||
@r##"[
|
||||
CompletionItem {
|
||||
label: "foo",
|
||||
source_range: [50; 50),
|
||||
delete: [50; 50),
|
||||
insert: "foo!",
|
||||
kind: Macro,
|
||||
detail: "macro_rules! foo",
|
||||
},
|
||||
CompletionItem {
|
||||
label: "main",
|
||||
source_range: [50; 50),
|
||||
delete: [50; 50),
|
||||
insert: "main()$0",
|
||||
kind: Function,
|
||||
detail: "fn main()",
|
||||
},
|
||||
]"##
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn completes_macros_as_item() {
|
||||
assert_debug_snapshot!(
|
||||
do_reference_completion(
|
||||
"
|
||||
//- /main.rs
|
||||
macro_rules! foo {
|
||||
() => {}
|
||||
}
|
||||
|
||||
fn foo() {}
|
||||
|
||||
<|>
|
||||
"
|
||||
),
|
||||
@r##"[
|
||||
CompletionItem {
|
||||
label: "foo",
|
||||
source_range: [46; 46),
|
||||
delete: [46; 46),
|
||||
insert: "foo!",
|
||||
kind: Macro,
|
||||
detail: "macro_rules! foo",
|
||||
},
|
||||
]"##
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ use crate::completion::{
|
|||
CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions,
|
||||
};
|
||||
|
||||
use crate::display::{const_label, function_label, type_label};
|
||||
use crate::display::{const_label, function_label, macro_label, type_label};
|
||||
|
||||
impl Completions {
|
||||
pub(crate) fn add_field(
|
||||
|
@ -43,8 +43,14 @@ impl Completions {
|
|||
) {
|
||||
use hir::ModuleDef::*;
|
||||
|
||||
if let Some(macro_) = resolution.get_macros() {
|
||||
self.add_macro(ctx, Some(local_name.clone()), macro_);
|
||||
}
|
||||
|
||||
let def = resolution.as_ref().take_types().or_else(|| resolution.as_ref().take_values());
|
||||
let def = match def {
|
||||
// Only insert once if it is just a macro name
|
||||
None if resolution.get_macros().is_some() => return,
|
||||
None => {
|
||||
self.add(CompletionItem::new(
|
||||
CompletionKind::Reference,
|
||||
|
@ -98,6 +104,22 @@ impl Completions {
|
|||
self.add_function_with_name(ctx, None, func)
|
||||
}
|
||||
|
||||
fn add_macro(&mut self, ctx: &CompletionContext, name: Option<String>, macro_: hir::MacroDef) {
|
||||
let ast_node = macro_.source(ctx.db).ast;
|
||||
if let Some(name) = name {
|
||||
let detail = macro_label(&ast_node);
|
||||
|
||||
let builder =
|
||||
CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.clone())
|
||||
.kind(CompletionItemKind::Macro)
|
||||
.set_documentation(macro_.docs(ctx.db))
|
||||
.detail(detail)
|
||||
.insert_snippet(format!("{}!", name));
|
||||
|
||||
self.add(builder);
|
||||
}
|
||||
}
|
||||
|
||||
fn add_function_with_name(
|
||||
&mut self,
|
||||
ctx: &CompletionContext,
|
||||
|
|
|
@ -7,7 +7,7 @@ mod structure;
|
|||
mod short_label;
|
||||
|
||||
use ra_syntax::{
|
||||
ast::{self, AstNode, TypeParamsOwner},
|
||||
ast::{self, AstNode, AttrsOwner, NameOwner, TypeParamsOwner},
|
||||
SyntaxKind::{ATTR, COMMENT},
|
||||
};
|
||||
|
||||
|
@ -61,6 +61,12 @@ pub(crate) fn where_predicates<N: TypeParamsOwner>(node: &N) -> Vec<String> {
|
|||
res
|
||||
}
|
||||
|
||||
pub(crate) fn macro_label(node: &ast::MacroCall) -> String {
|
||||
let name = node.name().map(|name| name.syntax().text().to_string()).unwrap_or_default();
|
||||
let vis = if node.has_atom_attr("macro_export") { "#[macro_export]\n" } else { "" };
|
||||
format!("{}macro_rules! {}", vis, name)
|
||||
}
|
||||
|
||||
pub(crate) fn rust_code_markup<CODE: AsRef<str>>(val: CODE) -> String {
|
||||
rust_code_markup_with_doc::<_, &str>(val, None)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue