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_string(&self, sp: Span) -> String;
|
||||||
fn span_to_filename(&self, sp: Span) -> FileName;
|
fn span_to_filename(&self, sp: Span) -> FileName;
|
||||||
fn macro_backtrace(&self, span: Span) -> Vec<MacroBacktrace>;
|
fn macro_backtrace(&self, span: Span) -> Vec<MacroBacktrace>;
|
||||||
|
fn merge_spans(&self, sp_lhs: Span, sp_rhs: Span) -> Option<Span>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CodeSuggestion {
|
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 {
|
pub fn span_to_string(&self, sp: Span) -> String {
|
||||||
if sp == COMMAND_LINE_SP {
|
if sp == COMMAND_LINE_SP {
|
||||||
return "<command line option>".to_string();
|
return "<command line option>".to_string();
|
||||||
|
@ -819,6 +859,9 @@ impl CodeMapper for CodeMap {
|
||||||
fn macro_backtrace(&self, span: Span) -> Vec<MacroBacktrace> {
|
fn macro_backtrace(&self, span: Span) -> Vec<MacroBacktrace> {
|
||||||
self.macro_backtrace(span)
|
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");
|
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
|
/// Returns the span corresponding to the `n`th occurrence of
|
||||||
/// `substring` in `source_text`.
|
/// `substring` in `source_text`.
|
||||||
trait CodeMapExtension {
|
trait CodeMapExtension {
|
||||||
|
|
|
@ -96,24 +96,6 @@ impl Span {
|
||||||
self.lo == other.lo && self.hi == other.hi
|
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`
|
/// Returns `Some(span)`, where the start is trimmed by the end of `other`
|
||||||
pub fn trim_start(self, other: Span) -> Option<Span> {
|
pub fn trim_start(self, other: Span) -> Option<Span> {
|
||||||
if self.hi > other.hi {
|
if self.hi > other.hi {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue