Add the ability to merge spans to codemap
This commit is contained in:
parent
8394685b83
commit
2ea3ab3a90
3 changed files with 83 additions and 18 deletions
|
@ -81,6 +81,7 @@ pub trait CodeMapper {
|
|||
fn span_to_string(&self, sp: Span) -> String;
|
||||
fn span_to_filename(&self, sp: Span) -> FileName;
|
||||
fn macro_backtrace(&self, span: Span) -> Vec<MacroBacktrace>;
|
||||
fn merge_spans(&self, sp_lhs: Span, sp_rhs: Span) -> Option<Span>;
|
||||
}
|
||||
|
||||
impl CodeSuggestion {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -96,24 +96,6 @@ impl Span {
|
|||
self.lo == other.lo && self.hi == other.hi
|
||||
}
|
||||
|
||||
/// Returns `Some(span)`, a union of `self` and `other`, on overlap.
|
||||
pub fn merge(self, other: Span) -> Option<Span> {
|
||||
if self.expn_id != other.expn_id {
|
||||
return None;
|
||||
}
|
||||
|
||||
if (self.lo <= other.lo && self.hi > other.lo) ||
|
||||
(self.lo >= other.lo && self.lo < other.hi) {
|
||||
Some(Span {
|
||||
lo: cmp::min(self.lo, other.lo),
|
||||
hi: cmp::max(self.hi, other.hi),
|
||||
expn_id: self.expn_id,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `Some(span)`, where the start is trimmed by the end of `other`
|
||||
pub fn trim_start(self, other: Span) -> Option<Span> {
|
||||
if self.hi > other.hi {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue