mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-30 22:01:37 +00:00
Auto merge of #18131 - ChayimFriedman2:macro-expand-dollar-crate, r=Veykril
fix: Get rid of `$crate` in expansions shown to the user Be it "Expand Macro Recursively", "Inline macro" or few other things. We replace it with the crate name, as should've always been. Probably fixes some issues, but I don't know what they are.
This commit is contained in:
commit
990c48cb0d
15 changed files with 396 additions and 64 deletions
|
@ -1,9 +1,10 @@
|
|||
use hir::db::ExpandDatabase;
|
||||
use hir::{InFile, MacroFileIdExt, Semantics};
|
||||
use ide_db::base_db::CrateId;
|
||||
use ide_db::{
|
||||
helpers::pick_best_token, syntax_helpers::insert_whitespace_into_node::insert_ws_into, FileId,
|
||||
RootDatabase,
|
||||
helpers::pick_best_token, syntax_helpers::prettify_macro_expansion, FileId, RootDatabase,
|
||||
};
|
||||
use span::Edition;
|
||||
use span::{Edition, SpanMap, SyntaxContextId, TextRange, TextSize};
|
||||
use syntax::{ast, ted, AstNode, NodeOrToken, SyntaxKind, SyntaxNode, T};
|
||||
|
||||
use crate::FilePosition;
|
||||
|
@ -27,6 +28,7 @@ pub struct ExpandedMacro {
|
|||
pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option<ExpandedMacro> {
|
||||
let sema = Semantics::new(db);
|
||||
let file = sema.parse_guess_edition(position.file_id);
|
||||
let krate = sema.file_to_module_def(position.file_id)?.krate().into();
|
||||
|
||||
let tok = pick_best_token(file.syntax().token_at_offset(position.offset), |kind| match kind {
|
||||
SyntaxKind::IDENT => 1,
|
||||
|
@ -61,8 +63,17 @@ pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option<
|
|||
.take_while(|it| it != &token)
|
||||
.filter(|it| it.kind() == T![,])
|
||||
.count();
|
||||
let expansion =
|
||||
format(db, SyntaxKind::MACRO_ITEMS, position.file_id, expansions.get(idx).cloned()?);
|
||||
let expansion = expansions.get(idx)?.clone();
|
||||
let expansion_file_id = sema.hir_file_for(&expansion).macro_file()?;
|
||||
let expansion_span_map = db.expansion_span_map(expansion_file_id);
|
||||
let expansion = format(
|
||||
db,
|
||||
SyntaxKind::MACRO_ITEMS,
|
||||
position.file_id,
|
||||
expansion,
|
||||
&expansion_span_map,
|
||||
krate,
|
||||
);
|
||||
Some(ExpandedMacro { name, expansion })
|
||||
});
|
||||
|
||||
|
@ -71,6 +82,7 @@ pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option<
|
|||
}
|
||||
|
||||
let mut anc = tok.parent_ancestors();
|
||||
let mut span_map = SpanMap::empty();
|
||||
let (name, expanded, kind) = loop {
|
||||
let node = anc.next()?;
|
||||
|
||||
|
@ -85,7 +97,7 @@ pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option<
|
|||
.unwrap_or(Edition::CURRENT),
|
||||
)
|
||||
.to_string(),
|
||||
expand_macro_recur(&sema, &item)?,
|
||||
expand_macro_recur(&sema, &item, &mut span_map, TextSize::new(0))?,
|
||||
SyntaxKind::MACRO_ITEMS,
|
||||
);
|
||||
}
|
||||
|
@ -95,14 +107,23 @@ pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option<
|
|||
name.push('!');
|
||||
let syntax_kind =
|
||||
mac.syntax().parent().map(|it| it.kind()).unwrap_or(SyntaxKind::MACRO_ITEMS);
|
||||
break (name, expand_macro_recur(&sema, &ast::Item::MacroCall(mac))?, syntax_kind);
|
||||
break (
|
||||
name,
|
||||
expand_macro_recur(
|
||||
&sema,
|
||||
&ast::Item::MacroCall(mac),
|
||||
&mut span_map,
|
||||
TextSize::new(0),
|
||||
)?,
|
||||
syntax_kind,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
// FIXME:
|
||||
// macro expansion may lose all white space information
|
||||
// But we hope someday we can use ra_fmt for that
|
||||
let expansion = format(db, kind, position.file_id, expanded);
|
||||
let expansion = format(db, kind, position.file_id, expanded, &span_map, krate);
|
||||
|
||||
Some(ExpandedMacro { name, expansion })
|
||||
}
|
||||
|
@ -110,6 +131,8 @@ pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option<
|
|||
fn expand_macro_recur(
|
||||
sema: &Semantics<'_, RootDatabase>,
|
||||
macro_call: &ast::Item,
|
||||
result_span_map: &mut SpanMap<SyntaxContextId>,
|
||||
offset_in_original_node: TextSize,
|
||||
) -> Option<SyntaxNode> {
|
||||
let expanded = match macro_call {
|
||||
item @ ast::Item::MacroCall(macro_call) => sema
|
||||
|
@ -118,29 +141,54 @@ fn expand_macro_recur(
|
|||
.clone_for_update(),
|
||||
item => sema.expand_attr_macro(item)?.clone_for_update(),
|
||||
};
|
||||
expand(sema, expanded)
|
||||
let file_id =
|
||||
sema.hir_file_for(&expanded).macro_file().expect("expansion must produce a macro file");
|
||||
let expansion_span_map = sema.db.expansion_span_map(file_id);
|
||||
result_span_map.merge(
|
||||
TextRange::at(offset_in_original_node, macro_call.syntax().text_range().len()),
|
||||
expanded.text_range().len(),
|
||||
&expansion_span_map,
|
||||
);
|
||||
Some(expand(sema, expanded, result_span_map, offset_in_original_node))
|
||||
}
|
||||
|
||||
fn expand(sema: &Semantics<'_, RootDatabase>, expanded: SyntaxNode) -> Option<SyntaxNode> {
|
||||
fn expand(
|
||||
sema: &Semantics<'_, RootDatabase>,
|
||||
expanded: SyntaxNode,
|
||||
result_span_map: &mut SpanMap<SyntaxContextId>,
|
||||
offset_in_original_node: TextSize,
|
||||
) -> SyntaxNode {
|
||||
let children = expanded.descendants().filter_map(ast::Item::cast);
|
||||
let mut replacements = Vec::new();
|
||||
|
||||
for child in children {
|
||||
if let Some(new_node) = expand_macro_recur(sema, &child) {
|
||||
if let Some(new_node) = expand_macro_recur(
|
||||
sema,
|
||||
&child,
|
||||
result_span_map,
|
||||
offset_in_original_node + child.syntax().text_range().start(),
|
||||
) {
|
||||
// check if the whole original syntax is replaced
|
||||
if expanded == *child.syntax() {
|
||||
return Some(new_node);
|
||||
return new_node;
|
||||
}
|
||||
replacements.push((child, new_node));
|
||||
}
|
||||
}
|
||||
|
||||
replacements.into_iter().rev().for_each(|(old, new)| ted::replace(old.syntax(), new));
|
||||
Some(expanded)
|
||||
expanded
|
||||
}
|
||||
|
||||
fn format(db: &RootDatabase, kind: SyntaxKind, file_id: FileId, expanded: SyntaxNode) -> String {
|
||||
let expansion = insert_ws_into(expanded).to_string();
|
||||
fn format(
|
||||
db: &RootDatabase,
|
||||
kind: SyntaxKind,
|
||||
file_id: FileId,
|
||||
expanded: SyntaxNode,
|
||||
span_map: &SpanMap<SyntaxContextId>,
|
||||
krate: CrateId,
|
||||
) -> String {
|
||||
let expansion = prettify_macro_expansion(db, expanded, span_map, krate).to_string();
|
||||
|
||||
_format(db, kind, file_id, &expansion).unwrap_or(expansion)
|
||||
}
|
||||
|
@ -498,7 +546,7 @@ struct Foo {}
|
|||
"#,
|
||||
expect![[r#"
|
||||
Clone
|
||||
impl < >$crate::clone::Clone for Foo< >where {
|
||||
impl < >core::clone::Clone for Foo< >where {
|
||||
fn clone(&self) -> Self {
|
||||
match self {
|
||||
Foo{}
|
||||
|
@ -524,7 +572,7 @@ struct Foo {}
|
|||
"#,
|
||||
expect![[r#"
|
||||
Copy
|
||||
impl < >$crate::marker::Copy for Foo< >where{}"#]],
|
||||
impl < >core::marker::Copy for Foo< >where{}"#]],
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -539,7 +587,7 @@ struct Foo {}
|
|||
"#,
|
||||
expect![[r#"
|
||||
Copy
|
||||
impl < >$crate::marker::Copy for Foo< >where{}"#]],
|
||||
impl < >core::marker::Copy for Foo< >where{}"#]],
|
||||
);
|
||||
check(
|
||||
r#"
|
||||
|
@ -550,7 +598,7 @@ struct Foo {}
|
|||
"#,
|
||||
expect![[r#"
|
||||
Clone
|
||||
impl < >$crate::clone::Clone for Foo< >where {
|
||||
impl < >core::clone::Clone for Foo< >where {
|
||||
fn clone(&self) -> Self {
|
||||
match self {
|
||||
Foo{}
|
||||
|
@ -563,4 +611,44 @@ struct Foo {}
|
|||
}"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dollar_crate() {
|
||||
check(
|
||||
r#"
|
||||
//- /a.rs crate:a
|
||||
pub struct Foo;
|
||||
#[macro_export]
|
||||
macro_rules! m {
|
||||
( $i:ident ) => { $crate::Foo; $crate::Foo; $i::Foo; };
|
||||
}
|
||||
//- /b.rs crate:b deps:a
|
||||
pub struct Foo;
|
||||
#[macro_export]
|
||||
macro_rules! m {
|
||||
() => { a::m!($crate); $crate::Foo; $crate::Foo; };
|
||||
}
|
||||
//- /c.rs crate:c deps:b,a
|
||||
pub struct Foo;
|
||||
#[macro_export]
|
||||
macro_rules! m {
|
||||
() => { b::m!(); $crate::Foo; $crate::Foo; };
|
||||
}
|
||||
fn bar() {
|
||||
m$0!();
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
m!
|
||||
a::Foo;
|
||||
a::Foo;
|
||||
b::Foo;
|
||||
;
|
||||
b::Foo;
|
||||
b::Foo;
|
||||
;
|
||||
crate::Foo;
|
||||
crate::Foo;"#]],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,9 +3,9 @@ use std::{mem, ops::Not};
|
|||
|
||||
use either::Either;
|
||||
use hir::{
|
||||
Adt, AsAssocItem, AsExternAssocItem, CaptureKind, HasCrate, HasSource, HirDisplay, Layout,
|
||||
LayoutError, MethodViolationCode, Name, ObjectSafetyViolation, Semantics, Trait, Type,
|
||||
TypeInfo,
|
||||
db::ExpandDatabase, Adt, AsAssocItem, AsExternAssocItem, CaptureKind, HasCrate, HasSource,
|
||||
HirDisplay, Layout, LayoutError, MethodViolationCode, Name, ObjectSafetyViolation, Semantics,
|
||||
Trait, Type, TypeInfo,
|
||||
};
|
||||
use ide_db::{
|
||||
base_db::SourceDatabase,
|
||||
|
@ -13,7 +13,7 @@ use ide_db::{
|
|||
documentation::HasDocs,
|
||||
famous_defs::FamousDefs,
|
||||
generated::lints::{CLIPPY_LINTS, DEFAULT_LINTS, FEATURES},
|
||||
syntax_helpers::insert_whitespace_into_node,
|
||||
syntax_helpers::prettify_macro_expansion,
|
||||
RootDatabase,
|
||||
};
|
||||
use itertools::Itertools;
|
||||
|
@ -476,8 +476,9 @@ pub(super) fn definition(
|
|||
Err(_) => {
|
||||
let source = it.source(db)?;
|
||||
let mut body = source.value.body()?.syntax().clone();
|
||||
if source.file_id.is_macro() {
|
||||
body = insert_whitespace_into_node::insert_ws_into(body);
|
||||
if let Some(macro_file) = source.file_id.macro_file() {
|
||||
let span_map = db.expansion_span_map(macro_file);
|
||||
body = prettify_macro_expansion(db, body, &span_map, it.krate(db).into());
|
||||
}
|
||||
Some(body.to_string())
|
||||
}
|
||||
|
@ -486,8 +487,9 @@ pub(super) fn definition(
|
|||
Definition::Static(it) => {
|
||||
let source = it.source(db)?;
|
||||
let mut body = source.value.body()?.syntax().clone();
|
||||
if source.file_id.is_macro() {
|
||||
body = insert_whitespace_into_node::insert_ws_into(body);
|
||||
if let Some(macro_file) = source.file_id.macro_file() {
|
||||
let span_map = db.expansion_span_map(macro_file);
|
||||
body = prettify_macro_expansion(db, body, &span_map, it.krate(db).into());
|
||||
}
|
||||
Some(body.to_string())
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue