about summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
authorJonathan Turner <jturner@mozilla.com>2016-09-19 12:31:56 -0700
committerJonathan Turner <jturner@mozilla.com>2016-09-19 12:31:56 -0700
commit2ea3ab3a9022a93e45c4d50a1c43aec5f56ab4dc (patch)
tree28b2c21cf26ac97dd70651b1970bdab4c462b816 /src/libsyntax
parent8394685b8385156fc4bc31cfbc693867e276d9d7 (diff)
downloadrust-2ea3ab3a9022a93e45c4d50a1c43aec5f56ab4dc.tar.gz
rust-2ea3ab3a9022a93e45c4d50a1c43aec5f56ab4dc.zip
Add the ability to merge spans to codemap
Diffstat (limited to 'src/libsyntax')
-rw-r--r--src/libsyntax/codemap.rs82
1 files changed, 82 insertions, 0 deletions
diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs
index cd6f2874954..ce15bd89590 100644
--- a/src/libsyntax/codemap.rs
+++ b/src/libsyntax/codemap.rs
@@ -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 {