mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-01 06:11:35 +00:00
Simplify macro rendering, remove constructor structs
This commit is contained in:
parent
2b60d80eaf
commit
97f7865c56
3 changed files with 88 additions and 86 deletions
|
@ -47,8 +47,8 @@ impl<'a> RenderContext<'a> {
|
||||||
self.completion.source_range()
|
self.completion.source_range()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_deprecated(&self, node: impl HasAttrs) -> bool {
|
fn is_deprecated(&self, def: impl HasAttrs) -> bool {
|
||||||
let attrs = node.attrs(self.db());
|
let attrs = def.attrs(self.db());
|
||||||
attrs.by_key("deprecated").exists() || attrs.by_key("rustc_deprecated").exists()
|
attrs.by_key("deprecated").exists() || attrs.by_key("rustc_deprecated").exists()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,8 +71,8 @@ impl<'a> RenderContext<'a> {
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn docs(&self, node: impl HasAttrs) -> Option<hir::Documentation> {
|
fn docs(&self, def: impl HasAttrs) -> Option<hir::Documentation> {
|
||||||
node.docs(self.db())
|
def.docs(self.db())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
//! Renderer for macro invocations.
|
//! Renderer for macro invocations.
|
||||||
|
|
||||||
use either::Either;
|
use either::Either;
|
||||||
use hir::HasSource;
|
use hir::{db::HirDatabase, Documentation, HasSource};
|
||||||
use ide_db::SymbolKind;
|
use ide_db::SymbolKind;
|
||||||
use syntax::{
|
use syntax::{
|
||||||
display::{fn_as_proc_macro_label, macro_label},
|
display::{fn_as_proc_macro_label, macro_label},
|
||||||
|
@ -21,94 +21,96 @@ pub(crate) fn render_macro(
|
||||||
macro_: hir::MacroDef,
|
macro_: hir::MacroDef,
|
||||||
) -> Option<CompletionItem> {
|
) -> Option<CompletionItem> {
|
||||||
let _p = profile::span("render_macro");
|
let _p = profile::span("render_macro");
|
||||||
MacroRender::new(ctx, name, macro_).render(import_to_add)
|
render(ctx, name, macro_, import_to_add)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
fn render(
|
||||||
struct MacroRender<'a> {
|
ctx @ RenderContext { completion }: RenderContext<'_>,
|
||||||
ctx: RenderContext<'a>,
|
name: hir::Name,
|
||||||
name: SmolStr,
|
|
||||||
macro_: hir::MacroDef,
|
macro_: hir::MacroDef,
|
||||||
docs: Option<hir::Documentation>,
|
import_to_add: Option<ImportEdit>,
|
||||||
bra: &'static str,
|
) -> Option<CompletionItem> {
|
||||||
ket: &'static str,
|
let db = completion.db;
|
||||||
|
|
||||||
|
let source_range = if completion.is_immediately_after_macro_bang() {
|
||||||
|
cov_mark::hit!(completes_macro_call_if_cursor_at_bang_token);
|
||||||
|
completion.token.parent().map(|it| it.text_range())
|
||||||
|
} else {
|
||||||
|
Some(ctx.source_range())
|
||||||
|
}?;
|
||||||
|
|
||||||
|
let name = name.to_smol_str();
|
||||||
|
let docs = ctx.docs(macro_);
|
||||||
|
let docs_str = docs.as_ref().map(Documentation::as_str).unwrap_or_default();
|
||||||
|
let (bra, ket) =
|
||||||
|
if macro_.is_fn_like() { guess_macro_braces(&name, docs_str) } else { ("", "") };
|
||||||
|
|
||||||
|
let needs_bang = macro_.is_fn_like()
|
||||||
|
&& !matches!(completion.path_kind(), Some(PathKind::Mac | PathKind::Use));
|
||||||
|
|
||||||
|
let mut item = CompletionItem::new(
|
||||||
|
SymbolKind::from(macro_.kind()),
|
||||||
|
source_range,
|
||||||
|
label(&ctx, needs_bang, bra, ket, &name),
|
||||||
|
);
|
||||||
|
item.set_deprecated(ctx.is_deprecated(macro_))
|
||||||
|
.set_detail(detail(db, macro_))
|
||||||
|
.set_documentation(docs);
|
||||||
|
|
||||||
|
if let Some(import_to_add) = import_to_add {
|
||||||
|
item.add_import(import_to_add);
|
||||||
|
}
|
||||||
|
|
||||||
|
let name = &*name;
|
||||||
|
|
||||||
|
match ctx.snippet_cap() {
|
||||||
|
Some(cap) if needs_bang && !completion.path_is_call() => {
|
||||||
|
let snippet = format!("{}!{}$0{}", name, bra, ket);
|
||||||
|
let lookup = banged_name(name);
|
||||||
|
item.insert_snippet(cap, snippet).lookup_by(lookup);
|
||||||
|
}
|
||||||
|
_ if needs_bang => {
|
||||||
|
let banged_name = banged_name(name);
|
||||||
|
item.insert_text(banged_name.clone()).lookup_by(banged_name);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
cov_mark::hit!(dont_insert_macro_call_parens_unncessary);
|
||||||
|
item.insert_text(name);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Some(item.build())
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> MacroRender<'a> {
|
fn label(
|
||||||
fn new(ctx: RenderContext<'a>, name: hir::Name, macro_: hir::MacroDef) -> MacroRender<'a> {
|
ctx: &RenderContext<'_>,
|
||||||
let name = name.to_smol_str();
|
needs_bang: bool,
|
||||||
let docs = ctx.docs(macro_);
|
bra: &str,
|
||||||
let docs_str = docs.as_ref().map_or("", |s| s.as_str());
|
ket: &str,
|
||||||
let (bra, ket) =
|
name: &SmolStr,
|
||||||
if macro_.is_fn_like() { guess_macro_braces(&name, docs_str) } else { ("", "") };
|
) -> SmolStr {
|
||||||
|
if needs_bang {
|
||||||
MacroRender { ctx, name, macro_, docs, bra, ket }
|
if ctx.snippet_cap().is_some() {
|
||||||
}
|
SmolStr::from_iter([&*name, "!", bra, "…", ket])
|
||||||
|
|
||||||
fn render(self, import_to_add: Option<ImportEdit>) -> Option<CompletionItem> {
|
|
||||||
let source_range = if self.ctx.completion.is_immediately_after_macro_bang() {
|
|
||||||
cov_mark::hit!(completes_macro_call_if_cursor_at_bang_token);
|
|
||||||
self.ctx.completion.token.parent().map(|it| it.text_range())
|
|
||||||
} else {
|
} else {
|
||||||
Some(self.ctx.source_range())
|
banged_name(name)
|
||||||
}?;
|
|
||||||
let mut item =
|
|
||||||
CompletionItem::new(SymbolKind::from(self.macro_.kind()), source_range, self.label());
|
|
||||||
item.set_deprecated(self.ctx.is_deprecated(self.macro_)).set_detail(self.detail());
|
|
||||||
|
|
||||||
if let Some(import_to_add) = import_to_add {
|
|
||||||
item.add_import(import_to_add);
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
let needs_bang = self.macro_.is_fn_like()
|
name.clone()
|
||||||
&& !matches!(self.ctx.completion.path_kind(), Some(PathKind::Mac | PathKind::Use));
|
|
||||||
let has_parens = self.ctx.completion.path_is_call();
|
|
||||||
|
|
||||||
match self.ctx.snippet_cap() {
|
|
||||||
Some(cap) if needs_bang && !has_parens => {
|
|
||||||
let snippet = format!("{}!{}$0{}", self.name, self.bra, self.ket);
|
|
||||||
let lookup = self.banged_name();
|
|
||||||
item.insert_snippet(cap, snippet).lookup_by(lookup);
|
|
||||||
}
|
|
||||||
_ if needs_bang => {
|
|
||||||
let lookup = self.banged_name();
|
|
||||||
item.insert_text(self.banged_name()).lookup_by(lookup);
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
cov_mark::hit!(dont_insert_macro_call_parens_unncessary);
|
|
||||||
item.insert_text(&*self.name);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
item.set_documentation(self.docs);
|
|
||||||
Some(item.build())
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn needs_bang(&self) -> bool {
|
fn banged_name(name: &str) -> SmolStr {
|
||||||
!matches!(self.ctx.completion.path_kind(), Some(PathKind::Mac | PathKind::Use))
|
SmolStr::from_iter([name, "!"])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn label(&self) -> SmolStr {
|
fn detail(db: &dyn HirDatabase, macro_: hir::MacroDef) -> Option<String> {
|
||||||
if !self.macro_.is_fn_like() {
|
// FIXME: This is parsing the file!
|
||||||
self.name.clone()
|
let detail = match macro_.source(db)?.value {
|
||||||
} else if self.needs_bang() && self.ctx.snippet_cap().is_some() {
|
Either::Left(node) => macro_label(&node),
|
||||||
SmolStr::from_iter([&*self.name, "!", self.bra, "…", self.ket])
|
Either::Right(node) => fn_as_proc_macro_label(&node),
|
||||||
} else {
|
};
|
||||||
self.banged_name()
|
Some(detail)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn banged_name(&self) -> SmolStr {
|
|
||||||
SmolStr::from_iter([&*self.name, "!"])
|
|
||||||
}
|
|
||||||
|
|
||||||
fn detail(&self) -> Option<String> {
|
|
||||||
let detail = match self.macro_.source(self.ctx.db())?.value {
|
|
||||||
Either::Left(node) => macro_label(&node),
|
|
||||||
Either::Right(node) => fn_as_proc_macro_label(&node),
|
|
||||||
};
|
|
||||||
Some(detail)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn guess_macro_braces(macro_name: &str, docs: &str) -> (&'static str, &'static str) {
|
fn guess_macro_braces(macro_name: &str, docs: &str) -> (&'static str, &'static str) {
|
||||||
|
@ -147,7 +149,7 @@ mod tests {
|
||||||
fn dont_insert_macro_call_parens_unncessary() {
|
fn dont_insert_macro_call_parens_unncessary() {
|
||||||
cov_mark::check!(dont_insert_macro_call_parens_unncessary);
|
cov_mark::check!(dont_insert_macro_call_parens_unncessary);
|
||||||
check_edit(
|
check_edit(
|
||||||
"frobnicate!",
|
"frobnicate",
|
||||||
r#"
|
r#"
|
||||||
//- /main.rs crate:main deps:foo
|
//- /main.rs crate:main deps:foo
|
||||||
use foo::$0;
|
use foo::$0;
|
||||||
|
@ -161,7 +163,7 @@ use foo::frobnicate;
|
||||||
);
|
);
|
||||||
|
|
||||||
check_edit(
|
check_edit(
|
||||||
"frobnicate!",
|
"frobnicate",
|
||||||
r#"
|
r#"
|
||||||
macro_rules! frobnicate { () => () }
|
macro_rules! frobnicate { () => () }
|
||||||
fn main() { frob$0!(); }
|
fn main() { frob$0!(); }
|
||||||
|
|
|
@ -129,7 +129,7 @@ struct Bar;
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
st Foo
|
st Foo
|
||||||
ma foo! macro_rules! foo_
|
ma foo macro_rules! foo_
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue