Skip to content

Commit

Permalink
Add the ability to merge spans to codemap
Browse files Browse the repository at this point in the history
  • Loading branch information
Jonathan Turner committed Sep 19, 2016
1 parent 8394685 commit 2ea3ab3
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 18 deletions.
1 change: 1 addition & 0 deletions src/librustc_errors/lib.rs
Expand Up @@ -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 {
Expand Down
82 changes: 82 additions & 0 deletions src/libsyntax/codemap.rs
Expand Up @@ -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();
Expand Down Expand Up @@ -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)
}
}

// _____________________________________________________________________________
Expand Down Expand Up @@ -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 {
Expand Down
18 changes: 0 additions & 18 deletions src/libsyntax_pos/lib.rs
Expand Up @@ -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 {
Expand Down

0 comments on commit 2ea3ab3

Please sign in to comment.