diff options
Diffstat (limited to 'src/libsyntax/codemap.rs')
| -rw-r--r-- | src/libsyntax/codemap.rs | 218 |
1 files changed, 83 insertions, 135 deletions
diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 35aa827782d..228af27f4b1 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -32,8 +32,6 @@ use serialize::{Encodable, Decodable, Encoder, Decoder}; use ast::Name; -use errors::emitter::MAX_HIGHLIGHT_LINES; - // _____________________________________________________________________________ // Pos, BytePos, CharPos // @@ -51,7 +49,7 @@ pub struct BytePos(pub u32); /// A character offset. Because of multibyte utf8 characters, a byte offset /// is not equivalent to a character offset. The CodeMap will convert BytePos /// values to CharPos values as necessary. -#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)] pub struct CharPos(pub usize); // FIXME: Lots of boilerplate in these impls, but so far my attempts to fix @@ -132,13 +130,29 @@ pub struct Span { pub expn_id: ExpnId } -/// Spans are converted to MultiSpans just before error reporting, either automatically, -/// generated by line grouping, or manually constructed. -/// In the latter case care should be taken to ensure that spans are ordered, disjoint, -/// and point into the same FileMap. +/// A collection of spans. Spans have two orthogonal attributes: +/// +/// - they can be *primary spans*. In this case they are the locus of +/// the error, and would be rendered with `^^^`. +/// - they can have a *label*. In this case, the label is written next +/// to the mark in the snippet when we render. #[derive(Clone)] pub struct MultiSpan { - pub spans: Vec<Span> + primary_spans: Vec<Span>, + span_labels: Vec<(Span, String)>, +} + +#[derive(Clone, Debug)] +pub struct SpanLabel { + /// the span we are going to include in the final snippet + pub span: Span, + + /// is this a primary span? This is the "locus" of the message, + /// and is indicated with a `^^^^` underline, versus `----` + pub is_primary: bool, + + /// what label should we attach to this span (if any)? + pub label: Option<String>, } pub const DUMMY_SP: Span = Span { lo: BytePos(0), hi: BytePos(0), expn_id: NO_EXPANSION }; @@ -276,97 +290,76 @@ pub fn original_sp(cm: &CodeMap, sp: Span, enclosing_sp: Span) -> Span { impl MultiSpan { pub fn new() -> MultiSpan { - MultiSpan { spans: Vec::new() } + MultiSpan { + primary_spans: vec![], + span_labels: vec![] + } } - pub fn to_span_bounds(&self) -> Span { - assert!(!self.spans.is_empty()); - let Span { lo, expn_id, .. } = *self.spans.first().unwrap(); - let Span { hi, .. } = *self.spans.last().unwrap(); - Span { lo: lo, hi: hi, expn_id: expn_id } + pub fn from_span(primary_span: Span) -> MultiSpan { + MultiSpan { + primary_spans: vec![primary_span], + span_labels: vec![] + } } - /// Merges or inserts the given span into itself. - pub fn push_merge(&mut self, mut sp: Span) { - let mut idx_merged = None; - - for idx in 0.. { - let cur = match self.spans.get(idx) { - Some(s) => *s, - None => break, - }; - // Try to merge with a contained Span - if let Some(union) = cur.merge(sp) { - self.spans[idx] = union; - sp = union; - idx_merged = Some(idx); - break; - } - // Or insert into the first sorted position - if sp.hi <= cur.lo { - self.spans.insert(idx, sp); - idx_merged = Some(idx); - break; - } - } - if let Some(idx) = idx_merged { - // Merge with spans trailing the insertion/merging position - while (idx + 1) < self.spans.len() { - if let Some(union) = self.spans[idx + 1].merge(sp) { - self.spans[idx] = union; - self.spans.remove(idx + 1); - } else { - break; - } - } - } else { - self.spans.push(sp); + pub fn from_spans(vec: Vec<Span>) -> MultiSpan { + MultiSpan { + primary_spans: vec, + span_labels: vec![] } } - /// Inserts the given span into itself, for use with `end_highlight_lines`. - pub fn push_trim(&mut self, mut sp: Span) { - let mut prev = mk_sp(BytePos(0), BytePos(0)); + pub fn push_primary_span(&mut self, span: Span) { + self.primary_spans.push(span); + } - if let Some(first) = self.spans.get_mut(0) { - if first.lo > sp.lo { - // Prevent us here from spanning fewer lines - // because of trimming the start of the span - // (this should not be visible, because this method ought - // to not be used in conjunction with `highlight_lines`) - first.lo = sp.lo; - } + pub fn push_span_label(&mut self, span: Span, label: String) { + self.span_labels.push((span, label)); + } + + /// Selects the first primary span (if any) + pub fn primary_span(&self) -> Option<Span> { + self.primary_spans.first().cloned() + } + + /// Returns all primary spans. + pub fn primary_spans(&self) -> &[Span] { + &self.primary_spans + } + + /// Returns the strings to highlight. If we have an explicit set, + /// return those, otherwise just give back an (unlabeled) version + /// of the primary span. + pub fn span_labels(&self) -> Vec<SpanLabel> { + let is_primary = |span| self.primary_spans.contains(&span); + let mut span_labels = vec![]; + + for &(span, ref label) in &self.span_labels { + span_labels.push(SpanLabel { + span: span, + is_primary: is_primary(span), + label: Some(label.clone()) + }); } - for idx in 0.. { - if let Some(sp_trim) = sp.trim_start(prev) { - // Implies `sp.hi > prev.hi` - let cur = match self.spans.get(idx) { - Some(s) => *s, - None => { - sp = sp_trim; - break; - } - }; - // `cur` may overlap with `sp_trim` - if let Some(cur_trim) = cur.trim_start(sp_trim) { - // Implies `sp.hi < cur.hi` - self.spans.insert(idx, sp_trim); - self.spans[idx + 1] = cur_trim; - return; - } else if sp.hi == cur.hi { - return; - } - prev = cur; + for &span in &self.primary_spans { + if !span_labels.iter().any(|sl| sl.span == span) { + span_labels.push(SpanLabel { + span: span, + is_primary: true, + label: None + }); } } - self.spans.push(sp); + + span_labels } } impl From<Span> for MultiSpan { fn from(span: Span) -> MultiSpan { - MultiSpan { spans: vec![span] } + MultiSpan::from_span(span) } } @@ -929,6 +922,10 @@ impl CodeMap { } pub fn span_to_string(&self, sp: Span) -> String { + if sp == COMMAND_LINE_SP { + return "<command line option>".to_string(); + } + if self.files.borrow().is_empty() && sp.source_equal(&DUMMY_SP) { return "no-location".to_string(); } @@ -1099,12 +1096,16 @@ impl CodeMap { } pub fn span_to_lines(&self, sp: Span) -> FileLinesResult { + debug!("span_to_lines(sp={:?})", sp); + if sp.lo > sp.hi { return Err(SpanLinesError::IllFormedSpan(sp)); } let lo = self.lookup_char_pos(sp.lo); + debug!("span_to_lines: lo={:?}", lo); let hi = self.lookup_char_pos(sp.hi); + debug!("span_to_lines: hi={:?}", hi); if lo.file.start_pos != hi.file.start_pos { return Err(SpanLinesError::DistinctSources(DistinctSources { @@ -1184,59 +1185,6 @@ impl CodeMap { } } - /// Groups and sorts spans by lines into `MultiSpan`s, where `push` adds them to their group, - /// specifying the unification behaviour for overlapping spans. - /// Spans overflowing a line are put into their own one-element-group. - pub fn custom_group_spans<F>(&self, mut spans: Vec<Span>, push: F) -> Vec<MultiSpan> - where F: Fn(&mut MultiSpan, Span) - { - spans.sort_by(|a, b| a.lo.cmp(&b.lo)); - let mut groups = Vec::<MultiSpan>::new(); - let mut overflowing = vec![]; - let mut prev_expn = ExpnId(!2u32); - let mut prev_file = !0usize; - let mut prev_line = !0usize; - let mut err_size = 0; - - for sp in spans { - let line = self.lookup_char_pos(sp.lo).line; - let line_hi = self.lookup_char_pos(sp.hi).line; - if line != line_hi { - overflowing.push(sp.into()); - continue - } - let file = self.lookup_filemap_idx(sp.lo); - - if err_size < MAX_HIGHLIGHT_LINES && sp.expn_id == prev_expn && file == prev_file { - // `push` takes care of sorting, trimming, and merging - push(&mut groups.last_mut().unwrap(), sp); - if line != prev_line { - err_size += 1; - } - } else { - groups.push(sp.into()); - err_size = 1; - } - prev_expn = sp.expn_id; - prev_file = file; - prev_line = line; - } - groups.extend(overflowing); - groups - } - - /// Groups and sorts spans by lines into `MultiSpan`s, merging overlapping spans. - /// Spans overflowing a line are put into their own one-element-group. - pub fn group_spans(&self, spans: Vec<Span>) -> Vec<MultiSpan> { - self.custom_group_spans(spans, |msp, sp| msp.push_merge(sp)) - } - - /// Like `group_spans`, but trims overlapping spans instead of - /// merging them (for use with `end_highlight_lines`) - pub fn end_group_spans(&self, spans: Vec<Span>) -> Vec<MultiSpan> { - self.custom_group_spans(spans, |msp, sp| msp.push_trim(sp)) - } - pub fn get_filemap(&self, filename: &str) -> Rc<FileMap> { for fm in self.files.borrow().iter() { if filename == fm.name { |
