mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-25 12:33:33 +00:00
Make stringify!
prettify its input
This will insert whitespace if the invocation is inside another macro
This commit is contained in:
parent
f22eea9053
commit
d05eae6ada
6 changed files with 48 additions and 133 deletions
|
@ -1,7 +1,7 @@
|
||||||
//! Builtin macro
|
//! Builtin macro
|
||||||
use crate::{
|
use crate::{
|
||||||
db::AstDatabase, name, quote, AstId, CrateId, MacroCallId, MacroCallLoc, MacroDefId,
|
db::AstDatabase, name, quote, AstId, CrateId, MacroCallId, MacroCallLoc, MacroDefId,
|
||||||
MacroDefKind, TextSize,
|
MacroDefKind,
|
||||||
};
|
};
|
||||||
|
|
||||||
use base_db::{AnchoredPath, Edition, FileId};
|
use base_db::{AnchoredPath, Edition, FileId};
|
||||||
|
@ -148,25 +148,14 @@ fn line_expand(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stringify_expand(
|
fn stringify_expand(
|
||||||
db: &dyn AstDatabase,
|
_db: &dyn AstDatabase,
|
||||||
id: MacroCallId,
|
_id: MacroCallId,
|
||||||
_tt: &tt::Subtree,
|
tt: &tt::Subtree,
|
||||||
) -> ExpandResult<tt::Subtree> {
|
) -> ExpandResult<tt::Subtree> {
|
||||||
let loc = db.lookup_intern_macro(id);
|
let pretty = tt::pretty(&tt.token_trees);
|
||||||
|
|
||||||
let macro_content = {
|
|
||||||
let arg = match loc.kind.arg(db) {
|
|
||||||
Some(arg) => arg,
|
|
||||||
None => return ExpandResult::only_err(mbe::ExpandError::UnexpectedToken),
|
|
||||||
};
|
|
||||||
let macro_args = arg;
|
|
||||||
let text = macro_args.text();
|
|
||||||
let without_parens = TextSize::of('(')..text.len() - TextSize::of(')');
|
|
||||||
text.slice(without_parens).to_string()
|
|
||||||
};
|
|
||||||
|
|
||||||
let expanded = quote! {
|
let expanded = quote! {
|
||||||
#macro_content
|
#pretty
|
||||||
};
|
};
|
||||||
|
|
||||||
ExpandResult::ok(expanded)
|
ExpandResult::ok(expanded)
|
||||||
|
@ -685,7 +674,11 @@ mod tests {
|
||||||
r#"
|
r#"
|
||||||
#[rustc_builtin_macro]
|
#[rustc_builtin_macro]
|
||||||
macro_rules! stringify {() => {}}
|
macro_rules! stringify {() => {}}
|
||||||
stringify!(a b c)
|
stringify!(
|
||||||
|
a
|
||||||
|
b
|
||||||
|
c
|
||||||
|
)
|
||||||
"#,
|
"#,
|
||||||
expect![["\"a b c\""]],
|
expect![["\"a b c\""]],
|
||||||
);
|
);
|
||||||
|
|
|
@ -26,7 +26,7 @@ use base_db::{impl_intern_key, salsa, CrateId, FileId, FileRange};
|
||||||
use syntax::{
|
use syntax::{
|
||||||
algo::skip_trivia_token,
|
algo::skip_trivia_token,
|
||||||
ast::{self, AstNode, HasAttrs},
|
ast::{self, AstNode, HasAttrs},
|
||||||
Direction, SyntaxNode, SyntaxToken, TextRange, TextSize,
|
Direction, SyntaxNode, SyntaxToken, TextRange,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
|
|
@ -199,44 +199,7 @@ pub mod token_stream {
|
||||||
|
|
||||||
impl ToString for TokenStream {
|
impl ToString for TokenStream {
|
||||||
fn to_string(&self) -> String {
|
fn to_string(&self) -> String {
|
||||||
return tokentrees_to_text(&self.token_trees[..]);
|
tt::pretty(&self.token_trees)
|
||||||
|
|
||||||
fn tokentrees_to_text(tkns: &[tt::TokenTree]) -> String {
|
|
||||||
tkns.iter()
|
|
||||||
.fold((String::new(), true), |(last, last_to_joint), tkn| {
|
|
||||||
let s = [last, tokentree_to_text(tkn)].join(if last_to_joint {
|
|
||||||
""
|
|
||||||
} else {
|
|
||||||
" "
|
|
||||||
});
|
|
||||||
let mut is_joint = false;
|
|
||||||
if let tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) = tkn {
|
|
||||||
if punct.spacing == tt::Spacing::Joint {
|
|
||||||
is_joint = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(s, is_joint)
|
|
||||||
})
|
|
||||||
.0
|
|
||||||
}
|
|
||||||
|
|
||||||
fn tokentree_to_text(tkn: &tt::TokenTree) -> String {
|
|
||||||
match tkn {
|
|
||||||
tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => ident.text.clone().into(),
|
|
||||||
tt::TokenTree::Leaf(tt::Leaf::Literal(literal)) => literal.text.clone().into(),
|
|
||||||
tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) => format!("{}", punct.char),
|
|
||||||
tt::TokenTree::Subtree(subtree) => {
|
|
||||||
let content = tokentrees_to_text(&subtree.token_trees);
|
|
||||||
let (open, close) = match subtree.delimiter.map(|it| it.kind) {
|
|
||||||
None => ("", ""),
|
|
||||||
Some(tt::DelimiterKind::Brace) => ("{", "}"),
|
|
||||||
Some(tt::DelimiterKind::Parenthesis) => ("(", ")"),
|
|
||||||
Some(tt::DelimiterKind::Bracket) => ("[", "]"),
|
|
||||||
};
|
|
||||||
format!("{}{}{}", open, content, close)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -199,44 +199,7 @@ pub mod token_stream {
|
||||||
|
|
||||||
impl ToString for TokenStream {
|
impl ToString for TokenStream {
|
||||||
fn to_string(&self) -> String {
|
fn to_string(&self) -> String {
|
||||||
return tokentrees_to_text(&self.token_trees[..]);
|
tt::pretty(&self.token_trees)
|
||||||
|
|
||||||
fn tokentrees_to_text(tkns: &[tt::TokenTree]) -> String {
|
|
||||||
tkns.iter()
|
|
||||||
.fold((String::new(), true), |(last, last_to_joint), tkn| {
|
|
||||||
let s = [last, tokentree_to_text(tkn)].join(if last_to_joint {
|
|
||||||
""
|
|
||||||
} else {
|
|
||||||
" "
|
|
||||||
});
|
|
||||||
let mut is_joint = false;
|
|
||||||
if let tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) = tkn {
|
|
||||||
if punct.spacing == tt::Spacing::Joint {
|
|
||||||
is_joint = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(s, is_joint)
|
|
||||||
})
|
|
||||||
.0
|
|
||||||
}
|
|
||||||
|
|
||||||
fn tokentree_to_text(tkn: &tt::TokenTree) -> String {
|
|
||||||
match tkn {
|
|
||||||
tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => ident.text.clone().into(),
|
|
||||||
tt::TokenTree::Leaf(tt::Leaf::Literal(literal)) => literal.text.clone().into(),
|
|
||||||
tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) => format!("{}", punct.char),
|
|
||||||
tt::TokenTree::Subtree(subtree) => {
|
|
||||||
let content = tokentrees_to_text(&subtree.token_trees);
|
|
||||||
let (open, close) = match subtree.delimiter.map(|it| it.kind) {
|
|
||||||
None => ("", ""),
|
|
||||||
Some(tt::DelimiterKind::Brace) => ("{", "}"),
|
|
||||||
Some(tt::DelimiterKind::Parenthesis) => ("(", ")"),
|
|
||||||
Some(tt::DelimiterKind::Bracket) => ("[", "]"),
|
|
||||||
};
|
|
||||||
format!("{}{}{}", open, content, close)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -199,44 +199,7 @@ pub mod token_stream {
|
||||||
|
|
||||||
impl ToString for TokenStream {
|
impl ToString for TokenStream {
|
||||||
fn to_string(&self) -> String {
|
fn to_string(&self) -> String {
|
||||||
return tokentrees_to_text(&self.token_trees[..]);
|
tt::pretty(&self.token_trees)
|
||||||
|
|
||||||
fn tokentrees_to_text(tkns: &[tt::TokenTree]) -> String {
|
|
||||||
tkns.iter()
|
|
||||||
.fold((String::new(), true), |(last, last_to_joint), tkn| {
|
|
||||||
let s = [last, tokentree_to_text(tkn)].join(if last_to_joint {
|
|
||||||
""
|
|
||||||
} else {
|
|
||||||
" "
|
|
||||||
});
|
|
||||||
let mut is_joint = false;
|
|
||||||
if let tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) = tkn {
|
|
||||||
if punct.spacing == tt::Spacing::Joint {
|
|
||||||
is_joint = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(s, is_joint)
|
|
||||||
})
|
|
||||||
.0
|
|
||||||
}
|
|
||||||
|
|
||||||
fn tokentree_to_text(tkn: &tt::TokenTree) -> String {
|
|
||||||
match tkn {
|
|
||||||
tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => ident.text.clone().into(),
|
|
||||||
tt::TokenTree::Leaf(tt::Leaf::Literal(literal)) => literal.text.clone().into(),
|
|
||||||
tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) => format!("{}", punct.char),
|
|
||||||
tt::TokenTree::Subtree(subtree) => {
|
|
||||||
let content = tokentrees_to_text(&subtree.token_trees);
|
|
||||||
let (open, close) = match subtree.delimiter.map(|it| it.kind) {
|
|
||||||
None => ("", ""),
|
|
||||||
Some(tt::DelimiterKind::Brace) => ("{", "}"),
|
|
||||||
Some(tt::DelimiterKind::Parenthesis) => ("(", ")"),
|
|
||||||
Some(tt::DelimiterKind::Bracket) => ("[", "]"),
|
|
||||||
};
|
|
||||||
format!("{}{}{}", open, content, close)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -274,3 +274,36 @@ impl Subtree {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod buffer;
|
pub mod buffer;
|
||||||
|
|
||||||
|
pub fn pretty(tkns: &[TokenTree]) -> String {
|
||||||
|
fn tokentree_to_text(tkn: &TokenTree) -> String {
|
||||||
|
match tkn {
|
||||||
|
TokenTree::Leaf(Leaf::Ident(ident)) => ident.text.clone().into(),
|
||||||
|
TokenTree::Leaf(Leaf::Literal(literal)) => literal.text.clone().into(),
|
||||||
|
TokenTree::Leaf(Leaf::Punct(punct)) => format!("{}", punct.char),
|
||||||
|
TokenTree::Subtree(subtree) => {
|
||||||
|
let content = pretty(&subtree.token_trees);
|
||||||
|
let (open, close) = match subtree.delimiter.map(|it| it.kind) {
|
||||||
|
None => ("", ""),
|
||||||
|
Some(DelimiterKind::Brace) => ("{", "}"),
|
||||||
|
Some(DelimiterKind::Parenthesis) => ("(", ")"),
|
||||||
|
Some(DelimiterKind::Bracket) => ("[", "]"),
|
||||||
|
};
|
||||||
|
format!("{}{}{}", open, content, close)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tkns.iter()
|
||||||
|
.fold((String::new(), true), |(last, last_to_joint), tkn| {
|
||||||
|
let s = [last, tokentree_to_text(tkn)].join(if last_to_joint { "" } else { " " });
|
||||||
|
let mut is_joint = false;
|
||||||
|
if let TokenTree::Leaf(Leaf::Punct(punct)) = tkn {
|
||||||
|
if punct.spacing == Spacing::Joint {
|
||||||
|
is_joint = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(s, is_joint)
|
||||||
|
})
|
||||||
|
.0
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue