Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add the ability to merge spans to codemap #36585

Merged
merged 2 commits into from
Sep 22, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/librustc_errors/lib.rs
Original file line number Diff line number Diff line change
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
77 changes: 77 additions & 0 deletions src/libsyntax/codemap.rs
Original file line number Diff line number Diff line change
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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you expect spans to overlap sometimes? The only time I would expect that is if one is strictly larger than the other, in which case maybe this method shouldn't be used. If you agree, you could be stricter and require the sp.lhs.hi < sp.rhs.lo, rather than comparing both los

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 and we don't overlap
if (sp_lhs.lo <= sp_rhs.lo) && (sp_lhs.hi <= 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,40 @@ 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);

assert!(cm.merge_spans(span1, span2).is_none());
}

/// 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
Original file line number Diff line number Diff line change
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