Add the ability to merge spans to codemap
This commit is contained in:
@@ -364,6 +364,46 @@ impl CodeMap {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `Some(span)`, a union of the lhs and rhs span. The lhs must precede the rhs. If
|
||||
/// there are gaps between lhs and rhs, the resulting union will cross these gaps.
|
||||
/// For this to work, the spans have to be:
|
||||
/// * the expn_id of both spans much match
|
||||
/// * the lhs span needs to end on the same line the rhs span begins
|
||||
/// * the lhs span must start at or before the rhs span
|
||||
pub fn merge_spans(&self, sp_lhs: Span, sp_rhs: Span) -> Option<Span> {
|
||||
use std::cmp;
|
||||
|
||||
// make sure we're at the same expansion id
|
||||
if sp_lhs.expn_id != sp_rhs.expn_id {
|
||||
return None;
|
||||
}
|
||||
|
||||
let lhs_end = match self.lookup_line(sp_lhs.hi) {
|
||||
Ok(x) => x,
|
||||
Err(_) => return None
|
||||
};
|
||||
let rhs_begin = match self.lookup_line(sp_rhs.lo) {
|
||||
Ok(x) => x,
|
||||
Err(_) => return None
|
||||
};
|
||||
|
||||
// if we must cross lines to merge, don't merge
|
||||
if lhs_end.line != rhs_begin.line {
|
||||
return None;
|
||||
}
|
||||
|
||||
// ensure these follow the expected order
|
||||
if sp_lhs.lo <= sp_rhs.lo {
|
||||
Some(Span {
|
||||
lo: cmp::min(sp_lhs.lo, sp_rhs.lo),
|
||||
hi: cmp::max(sp_lhs.hi, sp_rhs.hi),
|
||||
expn_id: sp_lhs.expn_id,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn span_to_string(&self, sp: Span) -> String {
|
||||
if sp == COMMAND_LINE_SP {
|
||||
return "<command line option>".to_string();
|
||||
@@ -819,6 +859,9 @@ impl CodeMapper for CodeMap {
|
||||
fn macro_backtrace(&self, span: Span) -> Vec<MacroBacktrace> {
|
||||
self.macro_backtrace(span)
|
||||
}
|
||||
fn merge_spans(&self, sp_lhs: Span, sp_rhs: Span) -> Option<Span> {
|
||||
self.merge_spans(sp_lhs, sp_rhs)
|
||||
}
|
||||
}
|
||||
|
||||
// _____________________________________________________________________________
|
||||
@@ -1072,6 +1115,45 @@ mod tests {
|
||||
blork.rs:1:1: 1:12\n `first line.`\n");
|
||||
}
|
||||
|
||||
/// Test merging two spans on the same line
|
||||
#[test]
|
||||
fn span_merging() {
|
||||
let cm = CodeMap::new();
|
||||
let inputtext = "bbbb BB bb CCC\n";
|
||||
let selection1 = " ~~ \n";
|
||||
let selection2 = " ~~~\n";
|
||||
cm.new_filemap_and_lines("blork.rs", None, inputtext);
|
||||
let span1 = span_from_selection(inputtext, selection1);
|
||||
let span2 = span_from_selection(inputtext, selection2);
|
||||
|
||||
if let Some(sp) = cm.merge_spans(span1, span2) {
|
||||
let sstr = cm.span_to_expanded_string(sp);
|
||||
assert_eq!(sstr, "blork.rs:1:6: 1:15\n`BB bb CCC`\n");
|
||||
}
|
||||
else {
|
||||
assert!(false);
|
||||
}
|
||||
}
|
||||
|
||||
/// Test failing to merge two spans on different lines
|
||||
#[test]
|
||||
fn span_merging_fail() {
|
||||
let cm = CodeMap::new();
|
||||
let inputtext = "bbbb BB\ncc CCC\n";
|
||||
let selection1 = " ~~\n \n";
|
||||
let selection2 = " \n ~~~\n";
|
||||
cm.new_filemap_and_lines("blork.rs", None, inputtext);
|
||||
let span1 = span_from_selection(inputtext, selection1);
|
||||
let span2 = span_from_selection(inputtext, selection2);
|
||||
|
||||
if let Some(_) = cm.merge_spans(span1, span2) {
|
||||
assert!(false);
|
||||
}
|
||||
else {
|
||||
assert!(true);
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the span corresponding to the `n`th occurrence of
|
||||
/// `substring` in `source_text`.
|
||||
trait CodeMapExtension {
|
||||
|
||||
Reference in New Issue
Block a user