Auto merge of #29995 - DanielJCampbell:Expanded-Span-Printing, r=nrc
r? @nrc
This commit is contained in:
commit
6941b2569a
@ -807,6 +807,96 @@ impl CodeMap {
|
||||
hi.col.to_usize() + 1)).to_string()
|
||||
}
|
||||
|
||||
// Returns true if two spans have the same callee
|
||||
// (Assumes the same ExpnFormat implies same callee)
|
||||
fn match_callees(&self, sp_a: &Span, sp_b: &Span) -> bool {
|
||||
let fmt_a = self
|
||||
.with_expn_info(sp_a.expn_id,
|
||||
|ei| ei.map(|ei| ei.callee.format.clone()));
|
||||
|
||||
let fmt_b = self
|
||||
.with_expn_info(sp_b.expn_id,
|
||||
|ei| ei.map(|ei| ei.callee.format.clone()));
|
||||
fmt_a == fmt_b
|
||||
}
|
||||
|
||||
/// Returns a formatted string showing the expansion chain of a span
|
||||
///
|
||||
/// Spans are printed in the following format:
|
||||
///
|
||||
/// filename:start_line:col: end_line:col
|
||||
/// snippet
|
||||
/// Callee:
|
||||
/// Callee span
|
||||
/// Callsite:
|
||||
/// Callsite span
|
||||
///
|
||||
/// Callees and callsites are printed recursively (if available, otherwise header
|
||||
/// and span is omitted), expanding into their own callee/callsite spans.
|
||||
/// Each layer of recursion has an increased indent, and snippets are truncated
|
||||
/// to at most 50 characters. Finally, recursive calls to the same macro are squashed,
|
||||
/// with '...' used to represent any number of recursive calls.
|
||||
pub fn span_to_expanded_string(&self, sp: Span) -> String {
|
||||
self.span_to_expanded_string_internal(sp, "")
|
||||
}
|
||||
|
||||
fn span_to_expanded_string_internal(&self, sp:Span, indent: &str) -> String {
|
||||
let mut indent = indent.to_owned();
|
||||
let mut output = "".to_owned();
|
||||
let span_str = self.span_to_string(sp);
|
||||
let mut span_snip = self.span_to_snippet(sp)
|
||||
.unwrap_or("Snippet unavailable".to_owned());
|
||||
if span_snip.len() > 50 {
|
||||
span_snip.truncate(50);
|
||||
span_snip.push_str("...");
|
||||
}
|
||||
output.push_str(&format!("{}{}\n{}`{}`\n", indent, span_str, indent, span_snip));
|
||||
|
||||
if sp.expn_id == NO_EXPANSION || sp.expn_id == COMMAND_LINE_EXPN {
|
||||
return output;
|
||||
}
|
||||
|
||||
let mut callee = self.with_expn_info(sp.expn_id,
|
||||
|ei| ei.and_then(|ei| ei.callee.span.clone()));
|
||||
let mut callsite = self.with_expn_info(sp.expn_id,
|
||||
|ei| ei.map(|ei| ei.call_site.clone()));
|
||||
|
||||
indent.push_str(" ");
|
||||
let mut is_recursive = false;
|
||||
|
||||
while callee.is_some() && self.match_callees(&sp, &callee.unwrap()) {
|
||||
callee = self.with_expn_info(callee.unwrap().expn_id,
|
||||
|ei| ei.and_then(|ei| ei.callee.span.clone()));
|
||||
is_recursive = true;
|
||||
}
|
||||
if let Some(span) = callee {
|
||||
output.push_str(&indent);
|
||||
output.push_str("Callee:\n");
|
||||
if is_recursive {
|
||||
output.push_str(&indent);
|
||||
output.push_str("...\n");
|
||||
}
|
||||
output.push_str(&(self.span_to_expanded_string_internal(span, &indent)));
|
||||
}
|
||||
|
||||
is_recursive = false;
|
||||
while callsite.is_some() && self.match_callees(&sp, &callsite.unwrap()) {
|
||||
callsite = self.with_expn_info(callsite.unwrap().expn_id,
|
||||
|ei| ei.map(|ei| ei.call_site.clone()));
|
||||
is_recursive = true;
|
||||
}
|
||||
if let Some(span) = callsite {
|
||||
output.push_str(&indent);
|
||||
output.push_str("Callsite:\n");
|
||||
if is_recursive {
|
||||
output.push_str(&indent);
|
||||
output.push_str("...\n");
|
||||
}
|
||||
output.push_str(&(self.span_to_expanded_string_internal(span, &indent)));
|
||||
}
|
||||
output
|
||||
}
|
||||
|
||||
pub fn span_to_filename(&self, sp: Span) -> FileName {
|
||||
self.lookup_char_pos(sp.lo).file.name.to_string()
|
||||
}
|
||||
@ -1274,4 +1364,118 @@ mod tests {
|
||||
|
||||
assert_eq!(sstr, "blork.rs:2:1: 2:12");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn t10() {
|
||||
// Test span_to_expanded_string works in base case (no expansion)
|
||||
let cm = init_code_map();
|
||||
let span = Span { lo: BytePos(0), hi: BytePos(11), expn_id: NO_EXPANSION };
|
||||
let sstr = cm.span_to_expanded_string(span);
|
||||
assert_eq!(sstr, "blork.rs:1:1: 1:12\n`first line.`\n");
|
||||
|
||||
let span = Span { lo: BytePos(12), hi: BytePos(23), expn_id: NO_EXPANSION };
|
||||
let sstr = cm.span_to_expanded_string(span);
|
||||
assert_eq!(sstr, "blork.rs:2:1: 2:12\n`second line`\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn t11() {
|
||||
// Test span_to_expanded_string works with expansion
|
||||
use ast::Name;
|
||||
let cm = init_code_map();
|
||||
let root = Span { lo: BytePos(0), hi: BytePos(11), expn_id: NO_EXPANSION };
|
||||
let format = ExpnFormat::MacroBang(Name(0u32));
|
||||
let callee = NameAndSpan { format: format,
|
||||
allow_internal_unstable: false,
|
||||
span: None };
|
||||
|
||||
let info = ExpnInfo { call_site: root, callee: callee };
|
||||
let id = cm.record_expansion(info);
|
||||
let sp = Span { lo: BytePos(12), hi: BytePos(23), expn_id: id };
|
||||
|
||||
let sstr = cm.span_to_expanded_string(sp);
|
||||
assert_eq!(sstr,
|
||||
"blork.rs:2:1: 2:12\n`second line`\n Callsite:\n \
|
||||
blork.rs:1:1: 1:12\n `first line.`\n");
|
||||
}
|
||||
|
||||
fn init_expansion_chain(cm: &CodeMap) -> Span {
|
||||
// Creates an expansion chain containing two recursive calls
|
||||
// root -> expA -> expA -> expB -> expB -> end
|
||||
use ast::Name;
|
||||
|
||||
let root = Span { lo: BytePos(0), hi: BytePos(11), expn_id: NO_EXPANSION };
|
||||
|
||||
let format_root = ExpnFormat::MacroBang(Name(0u32));
|
||||
let callee_root = NameAndSpan { format: format_root,
|
||||
allow_internal_unstable: false,
|
||||
span: Some(root) };
|
||||
|
||||
let info_a1 = ExpnInfo { call_site: root, callee: callee_root };
|
||||
let id_a1 = cm.record_expansion(info_a1);
|
||||
let span_a1 = Span { lo: BytePos(12), hi: BytePos(23), expn_id: id_a1 };
|
||||
|
||||
let format_a = ExpnFormat::MacroBang(Name(1u32));
|
||||
let callee_a = NameAndSpan { format: format_a,
|
||||
allow_internal_unstable: false,
|
||||
span: Some(span_a1) };
|
||||
|
||||
let info_a2 = ExpnInfo { call_site: span_a1, callee: callee_a.clone() };
|
||||
let id_a2 = cm.record_expansion(info_a2);
|
||||
let span_a2 = Span { lo: BytePos(12), hi: BytePos(23), expn_id: id_a2 };
|
||||
|
||||
let info_b1 = ExpnInfo { call_site: span_a2, callee: callee_a };
|
||||
let id_b1 = cm.record_expansion(info_b1);
|
||||
let span_b1 = Span { lo: BytePos(25), hi: BytePos(36), expn_id: id_b1 };
|
||||
|
||||
let format_b = ExpnFormat::MacroBang(Name(2u32));
|
||||
let callee_b = NameAndSpan { format: format_b,
|
||||
allow_internal_unstable: false,
|
||||
span: None };
|
||||
|
||||
let info_b2 = ExpnInfo { call_site: span_b1, callee: callee_b.clone() };
|
||||
let id_b2 = cm.record_expansion(info_b2);
|
||||
let span_b2 = Span { lo: BytePos(25), hi: BytePos(36), expn_id: id_b2 };
|
||||
|
||||
let info_end = ExpnInfo { call_site: span_b2, callee: callee_b };
|
||||
let id_end = cm.record_expansion(info_end);
|
||||
Span { lo: BytePos(37), hi: BytePos(48), expn_id: id_end }
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn t12() {
|
||||
// Test span_to_expanded_string collapses recursive macros and handles
|
||||
// recursive callsite and callee expansions
|
||||
let cm = init_code_map();
|
||||
let end = init_expansion_chain(&cm);
|
||||
let sstr = cm.span_to_expanded_string(end);
|
||||
let res_str =
|
||||
r"blork2.rs:2:1: 2:12
|
||||
`second line`
|
||||
Callsite:
|
||||
...
|
||||
blork2.rs:1:1: 1:12
|
||||
`first line.`
|
||||
Callee:
|
||||
blork.rs:2:1: 2:12
|
||||
`second line`
|
||||
Callee:
|
||||
blork.rs:1:1: 1:12
|
||||
`first line.`
|
||||
Callsite:
|
||||
blork.rs:1:1: 1:12
|
||||
`first line.`
|
||||
Callsite:
|
||||
...
|
||||
blork.rs:2:1: 2:12
|
||||
`second line`
|
||||
Callee:
|
||||
blork.rs:1:1: 1:12
|
||||
`first line.`
|
||||
Callsite:
|
||||
blork.rs:1:1: 1:12
|
||||
`first line.`
|
||||
";
|
||||
assert_eq!(sstr, res_str);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user