Skip to content

Commit 2ea3ab3

Browse files
author
Jonathan Turner
committed
Add the ability to merge spans to codemap
1 parent 8394685 commit 2ea3ab3

File tree

3 files changed

+83
-18
lines changed

3 files changed

+83
-18
lines changed

src/librustc_errors/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ pub trait CodeMapper {
8181
fn span_to_string(&self, sp: Span) -> String;
8282
fn span_to_filename(&self, sp: Span) -> FileName;
8383
fn macro_backtrace(&self, span: Span) -> Vec<MacroBacktrace>;
84+
fn merge_spans(&self, sp_lhs: Span, sp_rhs: Span) -> Option<Span>;
8485
}
8586

8687
impl CodeSuggestion {

src/libsyntax/codemap.rs

+82
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,46 @@ impl CodeMap {
364364
}
365365
}
366366

367+
/// Returns `Some(span)`, a union of the lhs and rhs span. The lhs must precede the rhs. If
368+
/// there are gaps between lhs and rhs, the resulting union will cross these gaps.
369+
/// For this to work, the spans have to be:
370+
/// * the expn_id of both spans much match
371+
/// * the lhs span needs to end on the same line the rhs span begins
372+
/// * the lhs span must start at or before the rhs span
373+
pub fn merge_spans(&self, sp_lhs: Span, sp_rhs: Span) -> Option<Span> {
374+
use std::cmp;
375+
376+
// make sure we're at the same expansion id
377+
if sp_lhs.expn_id != sp_rhs.expn_id {
378+
return None;
379+
}
380+
381+
let lhs_end = match self.lookup_line(sp_lhs.hi) {
382+
Ok(x) => x,
383+
Err(_) => return None
384+
};
385+
let rhs_begin = match self.lookup_line(sp_rhs.lo) {
386+
Ok(x) => x,
387+
Err(_) => return None
388+
};
389+
390+
// if we must cross lines to merge, don't merge
391+
if lhs_end.line != rhs_begin.line {
392+
return None;
393+
}
394+
395+
// ensure these follow the expected order
396+
if sp_lhs.lo <= sp_rhs.lo {
397+
Some(Span {
398+
lo: cmp::min(sp_lhs.lo, sp_rhs.lo),
399+
hi: cmp::max(sp_lhs.hi, sp_rhs.hi),
400+
expn_id: sp_lhs.expn_id,
401+
})
402+
} else {
403+
None
404+
}
405+
}
406+
367407
pub fn span_to_string(&self, sp: Span) -> String {
368408
if sp == COMMAND_LINE_SP {
369409
return "<command line option>".to_string();
@@ -819,6 +859,9 @@ impl CodeMapper for CodeMap {
819859
fn macro_backtrace(&self, span: Span) -> Vec<MacroBacktrace> {
820860
self.macro_backtrace(span)
821861
}
862+
fn merge_spans(&self, sp_lhs: Span, sp_rhs: Span) -> Option<Span> {
863+
self.merge_spans(sp_lhs, sp_rhs)
864+
}
822865
}
823866

824867
// _____________________________________________________________________________
@@ -1072,6 +1115,45 @@ mod tests {
10721115
blork.rs:1:1: 1:12\n `first line.`\n");
10731116
}
10741117

1118+
/// Test merging two spans on the same line
1119+
#[test]
1120+
fn span_merging() {
1121+
let cm = CodeMap::new();
1122+
let inputtext = "bbbb BB bb CCC\n";
1123+
let selection1 = " ~~ \n";
1124+
let selection2 = " ~~~\n";
1125+
cm.new_filemap_and_lines("blork.rs", None, inputtext);
1126+
let span1 = span_from_selection(inputtext, selection1);
1127+
let span2 = span_from_selection(inputtext, selection2);
1128+
1129+
if let Some(sp) = cm.merge_spans(span1, span2) {
1130+
let sstr = cm.span_to_expanded_string(sp);
1131+
assert_eq!(sstr, "blork.rs:1:6: 1:15\n`BB bb CCC`\n");
1132+
}
1133+
else {
1134+
assert!(false);
1135+
}
1136+
}
1137+
1138+
/// Test failing to merge two spans on different lines
1139+
#[test]
1140+
fn span_merging_fail() {
1141+
let cm = CodeMap::new();
1142+
let inputtext = "bbbb BB\ncc CCC\n";
1143+
let selection1 = " ~~\n \n";
1144+
let selection2 = " \n ~~~\n";
1145+
cm.new_filemap_and_lines("blork.rs", None, inputtext);
1146+
let span1 = span_from_selection(inputtext, selection1);
1147+
let span2 = span_from_selection(inputtext, selection2);
1148+
1149+
if let Some(_) = cm.merge_spans(span1, span2) {
1150+
assert!(false);
1151+
}
1152+
else {
1153+
assert!(true);
1154+
}
1155+
}
1156+
10751157
/// Returns the span corresponding to the `n`th occurrence of
10761158
/// `substring` in `source_text`.
10771159
trait CodeMapExtension {

src/libsyntax_pos/lib.rs

-18
Original file line numberDiff line numberDiff line change
@@ -96,24 +96,6 @@ impl Span {
9696
self.lo == other.lo && self.hi == other.hi
9797
}
9898

99-
/// Returns `Some(span)`, a union of `self` and `other`, on overlap.
100-
pub fn merge(self, other: Span) -> Option<Span> {
101-
if self.expn_id != other.expn_id {
102-
return None;
103-
}
104-
105-
if (self.lo <= other.lo && self.hi > other.lo) ||
106-
(self.lo >= other.lo && self.lo < other.hi) {
107-
Some(Span {
108-
lo: cmp::min(self.lo, other.lo),
109-
hi: cmp::max(self.hi, other.hi),
110-
expn_id: self.expn_id,
111-
})
112-
} else {
113-
None
114-
}
115-
}
116-
11799
/// Returns `Some(span)`, where the start is trimmed by the end of `other`
118100
pub fn trim_start(self, other: Span) -> Option<Span> {
119101
if self.hi > other.hi {

0 commit comments

Comments
 (0)