(index<- )        ./libsyntax/codemap.rs

    git branch:    * master           5200215 auto merge of #14035 : alexcrichton/rust/experimental, r=huonw
    modified:    Fri May  9 13:02:28 2014
   1  // Copyright 2012 The Rust Project Developers. See the COPYRIGHT
   2  // file at the top-level directory of this distribution and at
   3  // http://rust-lang.org/COPYRIGHT.
   4  //
   5  // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
   6  // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
   7  // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
   8  // option. This file may not be copied, modified, or distributed
   9  // except according to those terms.
  10  
  11  /*!
  12  
  13  The CodeMap tracks all the source code used within a single crate, mapping
  14  from integer byte positions to the original source code location. Each bit of
  15  source parsed during crate parsing (typically files, in-memory strings, or
  16  various bits of macro expansion) cover a continuous range of bytes in the
  17  CodeMap and are represented by FileMaps. Byte positions are stored in `spans`
  18  and used pervasively in the compiler. They are absolute positions within the
  19  CodeMap, which upon request can be converted to line and column information,
  20  source code snippets, etc.
  21  
  22  */
  23  
  24  use serialize::{Encodable, Decodable, Encoder, Decoder};
  25  use std::cell::RefCell;
  26  use std::rc::Rc;
  27  use std::strbuf::StrBuf;
  28  
  29  pub trait Pos {
  30      fn from_uint(n: uint) -> Self;
  31      fn to_uint(&self) -> uint;
  32  }
  33  
  34  /// A byte offset. Keep this small (currently 32-bits), as AST contains
  35  /// a lot of them.
  36  #[deriving(Clone, Eq, TotalEq, Hash, Ord, Show)]
  37  pub struct BytePos(pub u32);
  38  
  39  /// A character offset. Because of multibyte utf8 characters, a byte offset
  40  /// is not equivalent to a character offset. The CodeMap will convert BytePos
  41  /// values to CharPos values as necessary.
  42  #[deriving(Eq, Hash, Ord, Show)]
  43  pub struct CharPos(pub uint);
  44  
  45  // FIXME: Lots of boilerplate in these impls, but so far my attempts to fix
  46  // have been unsuccessful
  47  
  48  impl Pos for BytePos {
  49      fn from_uint(nuint) -> BytePos { BytePos(n as u32) }
  50      fn to_uint(&self) -> uint { let BytePos(n) = *self; n as uint }
  51  }
  52  
  53  impl Add<BytePos, BytePos> for BytePos {
  54      fn add(&self, rhs&BytePos) -> BytePos {
  55          BytePos((self.to_uint() + rhs.to_uint()) as u32)
  56      }
  57  }
  58  
  59  impl Sub<BytePos, BytePos> for BytePos {
  60      fn sub(&self, rhs&BytePos) -> BytePos {
  61          BytePos((self.to_uint() - rhs.to_uint()) as u32)
  62      }
  63  }
  64  
  65  impl Pos for CharPos {
  66      fn from_uint(nuint) -> CharPos { CharPos(n) }
  67      fn to_uint(&self) -> uint { let CharPos(n) = *self; n }
  68  }
  69  
  70  impl Add<CharPos,CharPos> for CharPos {
  71      fn add(&self, rhs&CharPos) -> CharPos {
  72          CharPos(self.to_uint() + rhs.to_uint())
  73      }
  74  }
  75  
  76  impl Sub<CharPos,CharPos> for CharPos {
  77      fn sub(&self, rhs&CharPos) -> CharPos {
  78          CharPos(self.to_uint() - rhs.to_uint())
  79      }
  80  }
  81  
  82  /**
  83  Spans represent a region of code, used for error reporting. Positions in spans
  84  are *absolute* positions from the beginning of the codemap, not positions
  85  relative to FileMaps. Methods on the CodeMap can be used to relate spans back
  86  to the original source.
  87  */
  88  #[deriving(Clone, Show, Hash)]
  89  pub struct Span {
  90      pub lo: BytePos,
  91      pub hi: BytePos,
  92      /// Information about where the macro came from, if this piece of
  93      /// code was created by a macro expansion.
  94      pub expn_info: Option<@ExpnInfo>
  95  }
  96  
  97  pub static DUMMY_SP: Span = Span { lo: BytePos(0), hi: BytePos(0), expn_info: None };
  98  
  99  #[deriving(Clone, Eq, TotalEq, Encodable, Decodable, Hash)]
 100  pub struct Spanned<T> {
 101      pub node: T,
 102      pub span: Span,
 103  }
 104  
 105  impl Eq for Span {
 106      fn eq(&self, other&Span) -> bool {
 107          return (*self).lo == (*other).lo && (*self).hi == (*other).hi;
 108      }
 109      fn ne(&self, other&Span) -> bool { !(*self).eq(other) }
 110  }
 111  
 112  impl TotalEq for Span {}
 113  
 114  impl<S:Encoder<E>, E> Encodable<S, E> for Span {
 115      /* Note #1972 -- spans are encoded but not decoded */
 116      fn encode(&self, s&mut S) -> Result<(), E> {
 117          s.emit_nil()
 118      }
 119  }
 120  
 121  impl<D:Decoder<E>, E> Decodable<D, E> for Span {
 122      fn decode(_d&mut D) -> Result<Span, E> {
 123          Ok(DUMMY_SP)
 124      }
 125  }
 126  
 127  pub fn spanned<T>(loBytePos, hiBytePos, tT) -> Spanned<T> {
 128      respan(mk_sp(lo, hi), t)
 129  }
 130  
 131  pub fn respan<T>(spSpan, tT) -> Spanned<T> {
 132      Spanned {node: t, span: sp}
 133  }
 134  
 135  pub fn dummy_spanned<T>(tT) -> Spanned<T> {
 136      respan(DUMMY_SP, t)
 137  }
 138  
 139  /* assuming that we're not in macro expansion */
 140  pub fn mk_sp(loBytePos, hiBytePos) -> Span {
 141      Span {lo: lo, hi: hi, expn_info: None}
 142  }
 143  
 144  /// Return the span itself if it doesn't come from a macro expansion,
 145  /// otherwise return the call site span up to the `enclosing_sp` by
 146  /// following the `expn_info` chain.
 147  pub fn original_sp(spSpan, enclosing_spSpan) -> Span {
 148      match (sp.expn_info, enclosing_sp.expn_info) {
 149          (None, _) => sp,
 150          (Some(expn1), Some(expn2)) if expn1.call_site == expn2.call_site => sp,
 151          (Some(expn1), _) => original_sp(expn1.call_site, enclosing_sp),
 152      }
 153  }
 154  
 155  /// A source code location used for error reporting
 156  pub struct Loc {
 157      /// Information about the original source
 158      pub file: Rc<FileMap>,
 159      /// The (1-based) line number
 160      pub line: uint,
 161      /// The (0-based) column offset
 162      pub col: CharPos
 163  }
 164  
 165  /// A source code location used as the result of lookup_char_pos_adj
 166  // Actually, *none* of the clients use the filename *or* file field;
 167  // perhaps they should just be removed.
 168  pub struct LocWithOpt {
 169      pub filename: FileName,
 170      pub line: uint,
 171      pub col: CharPos,
 172      pub file: Option<Rc<FileMap>>,
 173  }
 174  
 175  // used to be structural records. Better names, anyone?
 176  pub struct FileMapAndLine { pub fm: Rc<FileMap>, pub line: uint }
 177  pub struct FileMapAndBytePos { pub fm: Rc<FileMap>, pub pos: BytePos }
 178  
 179  /// The syntax with which a macro was invoked.
 180  #[deriving(Clone, Hash, Show)]
 181  pub enum MacroFormat {
 182      /// e.g. #[deriving(...)] <item>
 183      MacroAttribute,
 184      /// e.g. `format!()`
 185      MacroBang
 186  }
 187  
 188  #[deriving(Clone, Hash, Show)]
 189  pub struct NameAndSpan {
 190      /// The name of the macro that was invoked to create the thing
 191      /// with this Span.
 192      pub name: StrBuf,
 193      /// The format with which the macro was invoked.
 194      pub format: MacroFormat,
 195      /// The span of the macro definition itself. The macro may not
 196      /// have a sensible definition span (e.g. something defined
 197      /// completely inside libsyntax) in which case this is None.
 198      pub span: Option<Span>
 199  }
 200  
 201  /// Extra information for tracking macro expansion of spans
 202  #[deriving(Hash, Show)]
 203  pub struct ExpnInfo {
 204      /// The location of the actual macro invocation, e.g. `let x =
 205      /// foo!();`
 206      ///
 207      /// This may recursively refer to other macro invocations, e.g. if
 208      /// `foo!()` invoked `bar!()` internally, and there was an
 209      /// expression inside `bar!`; the call_site of the expression in
 210      /// the expansion would point to the `bar!` invocation; that
 211      /// call_site span would have its own ExpnInfo, with the call_site
 212      /// pointing to the `foo!` invocation.
 213      pub call_site: Span,
 214      /// Information about the macro and its definition.
 215      ///
 216      /// The `callee` of the inner expression in the `call_site`
 217      /// example would point to the `macro_rules! bar { ... }` and that
 218      /// of the `bar!()` invocation would point to the `macro_rules!
 219      /// foo { ... }`.
 220      pub callee: NameAndSpan
 221  }
 222  
 223  pub type FileName = StrBuf;
 224  
 225  pub struct FileLines {
 226      pub file: Rc<FileMap>,
 227      pub lines: Vec<uint>
 228  }
 229  
 230  /// Identifies an offset of a multi-byte character in a FileMap
 231  pub struct MultiByteChar {
 232      /// The absolute offset of the character in the CodeMap
 233      pub pos: BytePos,
 234      /// The number of bytes, >=2
 235      pub bytes: uint,
 236  }
 237  
 238  /// A single source in the CodeMap
 239  pub struct FileMap {
 240      /// The name of the file that the source came from, source that doesn't
 241      /// originate from files has names between angle brackets by convention,
 242      /// e.g. `<anon>`
 243      pub name: FileName,
 244      /// The complete source code
 245      pub src: StrBuf,
 246      /// The start position of this source in the CodeMap
 247      pub start_pos: BytePos,
 248      /// Locations of lines beginnings in the source code
 249      pub lines: RefCell<Vec<BytePos> >,
 250      /// Locations of multi-byte characters in the source code
 251      pub multibyte_chars: RefCell<Vec<MultiByteChar> >,
 252  }
 253  
 254  impl FileMap {
 255      // EFFECT: register a start-of-line offset in the
 256      // table of line-beginnings.
 257      // UNCHECKED INVARIANT: these offsets must be added in the right
 258      // order and must be in the right places; there is shared knowledge
 259      // about what ends a line between this file and parse.rs
 260      // WARNING: pos param here is the offset relative to start of CodeMap,
 261      // and CodeMap will append a newline when adding a filemap without a newline at the end,
 262      // so the safe way to call this is with value calculated as
 263      // filemap.start_pos + newline_offset_relative_to_the_start_of_filemap.
 264      pub fn next_line(&self, posBytePos) {
 265          // the new charpos must be > the last one (or it's the first one).
 266          let mut lines = self.lines.borrow_mut();;
 267          let line_len = lines.len();
 268          assert!(line_len == 0 || (*lines.get(line_len - 1) < pos))
 269          lines.push(pos);
 270      }
 271  
 272      // get a line from the list of pre-computed line-beginnings
 273      pub fn get_line(&self, lineint) -> StrBuf {
 274          let mut lines = self.lines.borrow_mut();
 275          let beginBytePos = *lines.get(line as uint) - self.start_pos;
 276          let begin = begin.to_uint();
 277          let slice = self.src.as_slice().slice_from(begin);
 278          match slice.find('\n') {
 279              Some(e) => slice.slice_to(e).to_strbuf(),
 280              None => slice.to_strbuf()
 281          }
 282      }
 283  
 284      pub fn record_multibyte_char(&self, posBytePos, bytesuint) {
 285          assert!(bytes >=2 && bytes <= 4);
 286          let mbc = MultiByteChar {
 287              pos: pos,
 288              bytes: bytes,
 289          };
 290          self.multibyte_chars.borrow_mut().push(mbc);
 291      }
 292  
 293      pub fn is_real_file(&self) -> bool {
 294          !(self.name.as_slice().starts_with("<") &&
 295            self.name.as_slice().ends_with(">"))
 296      }
 297  }
 298  
 299  pub struct CodeMap {
 300      pub files: RefCell<Vec<Rc<FileMap>>>
 301  }
 302  
 303  impl CodeMap {
 304      pub fn new() -> CodeMap {
 305          CodeMap {
 306              files: RefCell::new(Vec::new()),
 307          }
 308      }
 309  
 310      pub fn new_filemap(&self, filenameFileName, srcStrBuf) -> Rc<FileMap> {
 311          let mut files = self.files.borrow_mut();
 312          let start_pos = match files.last() {
 313              None => 0,
 314              Some(last) => last.start_pos.to_uint() + last.src.len(),
 315          };
 316  
 317          // Remove utf-8 BOM if any.
 318          // FIXME #12884: no efficient/safe way to remove from the start of a string
 319          // and reuse the allocation.
 320          let mut src = if src.as_slice().starts_with("\ufeff") {
 321              StrBuf::from_str(src.as_slice().slice_from(3))
 322          } else {
 323              StrBuf::from_str(src.as_slice())
 324          };
 325  
 326          // Append '\n' in case it's not already there.
 327          // This is a workaround to prevent CodeMap.lookup_filemap_idx from accidentally
 328          // overflowing into the next filemap in case the last byte of span is also the last
 329          // byte of filemap, which leads to incorrect results from CodeMap.span_to_*.
 330          if src.len() > 0 && !src.as_slice().ends_with("\n") {
 331              src.push_char('\n');
 332          }
 333  
 334          let filemap = Rc::new(FileMap {
 335              name: filename,
 336              src: src.to_strbuf(),
 337              start_pos: Pos::from_uint(start_pos),
 338              lines: RefCell::new(Vec::new()),
 339              multibyte_chars: RefCell::new(Vec::new()),
 340          });
 341  
 342          files.push(filemap.clone());
 343  
 344          filemap
 345      }
 346  
 347      pub fn mk_substr_filename(&self, spSpan) -> StrBuf {
 348          let pos = self.lookup_char_pos(sp.lo);
 349          (format!("<{}:{}:{}>",
 350                   pos.file.name,
 351                   pos.line,
 352                   pos.col.to_uint() + 1)).to_strbuf()
 353      }
 354  
 355      /// Lookup source information about a BytePos
 356      pub fn lookup_char_pos(&self, posBytePos) -> Loc {
 357          self.lookup_pos(pos)
 358      }
 359  
 360      pub fn lookup_char_pos_adj(&self, posBytePos) -> LocWithOpt {
 361          let loc = self.lookup_char_pos(pos);
 362          LocWithOpt {
 363              filename: loc.file.name.to_strbuf(),
 364              line: loc.line,
 365              col: loc.col,
 366              file: Some(loc.file)
 367          }
 368      }
 369  
 370      pub fn span_to_str(&self, spSpan) -> StrBuf {
 371          if self.files.borrow().len() == 0 && sp == DUMMY_SP {
 372              return "no-location".to_strbuf();
 373          }
 374  
 375          let lo = self.lookup_char_pos_adj(sp.lo);
 376          let hi = self.lookup_char_pos_adj(sp.hi);
 377          return (format!("{}:{}:{}{}:{}",
 378                          lo.filename,
 379                          lo.line,
 380                          lo.col.to_uint() + 1,
 381                          hi.line,
 382                          hi.col.to_uint() + 1)).to_strbuf()
 383      }
 384  
 385      pub fn span_to_filename(&self, spSpan) -> FileName {
 386          self.lookup_char_pos(sp.lo).file.name.to_strbuf()
 387      }
 388  
 389      pub fn span_to_lines(&self, spSpan) -> FileLines {
 390          let lo = self.lookup_char_pos(sp.lo);
 391          let hi = self.lookup_char_pos(sp.hi);
 392          let mut lines = Vec::new();
 393          for i in range(lo.line - 1u, hi.line as uint) {
 394              lines.push(i);
 395          };
 396          FileLines {file: lo.file, lines: lines}
 397      }
 398  
 399      pub fn span_to_snippet(&self, spSpan) -> Option<StrBuf> {
 400          let begin = self.lookup_byte_offset(sp.lo);
 401          let end = self.lookup_byte_offset(sp.hi);
 402  
 403          // FIXME #8256: this used to be an assert but whatever precondition
 404          // it's testing isn't true for all spans in the AST, so to allow the
 405          // caller to not have to fail (and it can't catch it since the CodeMap
 406          // isn't sendable), return None
 407          if begin.fm.start_pos != end.fm.start_pos {
 408              None
 409          } else {
 410              Some(begin.fm.src.as_slice().slice(begin.pos.to_uint(),
 411                                                 end.pos.to_uint()).to_strbuf())
 412          }
 413      }
 414  
 415      pub fn get_filemap(&self, filename&str) -> Rc<FileMap> {
 416          for fm in self.files.borrow().iter() {
 417              if filename == fm.name.as_slice() {
 418                  return fm.clone();
 419              }
 420          }
 421          fail!("asking for {} which we don't know about", filename);
 422      }
 423  
 424      fn lookup_filemap_idx(&self, posBytePos) -> uint {
 425          let files = self.files.borrow();
 426          let files = files;
 427          let len = files.len();
 428          let mut a = 0u;
 429          let mut b = len;
 430          while b - a > 1u {
 431              let m = (a + b) / 2u;
 432              if files.get(m).start_pos > pos {
 433                  b = m;
 434              } else {
 435                  a = m;
 436              }
 437          }
 438          // There can be filemaps with length 0. These have the same start_pos as the previous
 439          // filemap, but are not the filemaps we want (because they are length 0, they cannot
 440          // contain what we are looking for). So, rewind until we find a useful filemap.
 441          loop {
 442              let lines = files.get(a).lines.borrow();
 443              let lines = lines;
 444              if lines.len() > 0 {
 445                  break;
 446              }
 447              if a == 0 {
 448                  fail!("position {} does not resolve to a source location", pos.to_uint());
 449              }
 450              a -= 1;
 451          }
 452          if a >= len {
 453              fail!("position {} does not resolve to a source location", pos.to_uint())
 454          }
 455  
 456          return a;
 457      }
 458  
 459      fn lookup_line(&self, posBytePos) -> FileMapAndLine {
 460          let idx = self.lookup_filemap_idx(pos);
 461  
 462          let files = self.files.borrow();
 463          let f = files.get(idx).clone();
 464          let mut a = 0u;
 465          {
 466              let mut lines = f.lines.borrow_mut();
 467              let mut b = lines.len();
 468              while b - a > 1u {
 469                  let m = (a + b) / 2u;
 470                  if *lines.get(m) > pos { b = m; } else { a = m; }
 471              }
 472          }
 473          FileMapAndLine {fm: f, line: a}
 474      }
 475  
 476      fn lookup_pos(&self, posBytePos) -> Loc {
 477          let FileMapAndLine {fm: f, line: a} = self.lookup_line(pos);
 478          let line = a + 1u; // Line numbers start at 1
 479          let chpos = self.bytepos_to_file_charpos(pos);
 480          let linebpos = *f.lines.borrow().get(a);
 481          let linechpos = self.bytepos_to_file_charpos(linebpos);
 482          debug!("codemap: byte pos {:?} is on the line at byte pos {:?}",
 483                 pos, linebpos);
 484          debug!("codemap: char pos {:?} is on the line at char pos {:?}",
 485                 chpos, linechpos);
 486          debug!("codemap: byte is on line: {:?}", line);
 487          assert!(chpos >= linechpos);
 488          Loc {
 489              file: f,
 490              line: line,
 491              col: chpos - linechpos
 492          }
 493      }
 494  
 495      fn lookup_byte_offset(&self, bposBytePos) -> FileMapAndBytePos {
 496          let idx = self.lookup_filemap_idx(bpos);
 497          let fm = self.files.borrow().get(idx).clone();
 498          let offset = bpos - fm.start_pos;
 499          FileMapAndBytePos {fm: fm, pos: offset}
 500      }
 501  
 502      // Converts an absolute BytePos to a CharPos relative to the filemap.
 503      fn bytepos_to_file_charpos(&self, bposBytePos) -> CharPos {
 504          debug!("codemap: converting {:?} to char pos", bpos);
 505          let idx = self.lookup_filemap_idx(bpos);
 506          let files = self.files.borrow();
 507          let map = files.get(idx);
 508  
 509          // The number of extra bytes due to multibyte chars in the FileMap
 510          let mut total_extra_bytes = 0;
 511  
 512          for mbc in map.multibyte_chars.borrow().iter() {
 513              debug!("codemap: {:?}-byte char at {:?}", mbc.bytes, mbc.pos);
 514              if mbc.pos < bpos {
 515                  // every character is at least one byte, so we only
 516                  // count the actual extra bytes.
 517                  total_extra_bytes += mbc.bytes - 1;
 518                  // We should never see a byte position in the middle of a
 519                  // character
 520                  assert!(bpos.to_uint() >= mbc.pos.to_uint() + mbc.bytes);
 521              } else {
 522                  break;
 523              }
 524          }
 525  
 526          assert!(map.start_pos.to_uint() + total_extra_bytes <= bpos.to_uint());
 527          CharPos(bpos.to_uint() - map.start_pos.to_uint() - total_extra_bytes)
 528      }
 529  }
 530  
 531  #[cfg(test)]
 532  mod test {
 533      use super::*;
 534  
 535      #[test]
 536      fn t1 () {
 537          let cm = CodeMap::new();
 538          let fm = cm.new_filemap("blork.rs".to_strbuf(),
 539                                  "first line.\nsecond line".to_strbuf());
 540          fm.next_line(BytePos(0));
 541          assert_eq!(&fm.get_line(0),&"first line.".to_strbuf());
 542          // TESTING BROKEN BEHAVIOR:
 543          fm.next_line(BytePos(10));
 544          assert_eq!(&fm.get_line(1), &".".to_strbuf());
 545      }
 546  
 547      #[test]
 548      #[should_fail]
 549      fn t2 () {
 550          let cm = CodeMap::new();
 551          let fm = cm.new_filemap("blork.rs".to_strbuf(),
 552                                  "first line.\nsecond line".to_strbuf());
 553          // TESTING *REALLY* BROKEN BEHAVIOR:
 554          fm.next_line(BytePos(0));
 555          fm.next_line(BytePos(10));
 556          fm.next_line(BytePos(2));
 557      }
 558  
 559      fn init_code_map() -> CodeMap {
 560          let cm = CodeMap::new();
 561          let fm1 = cm.new_filemap("blork.rs".to_strbuf(),
 562                                   "first line.\nsecond line".to_strbuf());
 563          let fm2 = cm.new_filemap("empty.rs".to_strbuf(),
 564                                   "".to_strbuf());
 565          let fm3 = cm.new_filemap("blork2.rs".to_strbuf(),
 566                                   "first line.\nsecond line".to_strbuf());
 567  
 568          fm1.next_line(BytePos(0));
 569          fm1.next_line(BytePos(12));
 570          fm2.next_line(BytePos(24));
 571          fm3.next_line(BytePos(24));
 572          fm3.next_line(BytePos(34));
 573  
 574          cm
 575      }
 576  
 577      #[test]
 578      fn t3() {
 579          // Test lookup_byte_offset
 580          let cm = init_code_map();
 581  
 582          let fmabp1 = cm.lookup_byte_offset(BytePos(22));
 583          assert_eq!(fmabp1.fm.name, "blork.rs".to_strbuf());
 584          assert_eq!(fmabp1.pos, BytePos(22));
 585  
 586          let fmabp2 = cm.lookup_byte_offset(BytePos(24));
 587          assert_eq!(fmabp2.fm.name, "blork2.rs".to_strbuf());
 588          assert_eq!(fmabp2.pos, BytePos(0));
 589      }
 590  
 591      #[test]
 592      fn t4() {
 593          // Test bytepos_to_file_charpos
 594          let cm = init_code_map();
 595  
 596          let cp1 = cm.bytepos_to_file_charpos(BytePos(22));
 597          assert_eq!(cp1, CharPos(22));
 598  
 599          let cp2 = cm.bytepos_to_file_charpos(BytePos(24));
 600          assert_eq!(cp2, CharPos(0));
 601      }
 602  
 603      #[test]
 604      fn t5() {
 605          // Test zero-length filemaps.
 606          let cm = init_code_map();
 607  
 608          let loc1 = cm.lookup_char_pos(BytePos(22));
 609          assert_eq!(loc1.file.name, "blork.rs".to_strbuf());
 610          assert_eq!(loc1.line, 2);
 611          assert_eq!(loc1.col, CharPos(10));
 612  
 613          let loc2 = cm.lookup_char_pos(BytePos(24));
 614          assert_eq!(loc2.file.name, "blork2.rs".to_strbuf());
 615          assert_eq!(loc2.line, 1);
 616          assert_eq!(loc2.col, CharPos(0));
 617      }
 618  
 619      fn init_code_map_mbc() -> CodeMap {
 620          let cm = CodeMap::new();
 621          // â‚¬ is a three byte utf8 char.
 622          let fm1 =
 623              cm.new_filemap("blork.rs".to_strbuf(),
 624                             "fir€st â‚¬â‚¬â‚¬â‚¬ line.\nsecond line".to_strbuf());
 625          let fm2 = cm.new_filemap("blork2.rs".to_strbuf(),
 626                                   "first line€€.\n€ second line".to_strbuf());
 627  
 628          fm1.next_line(BytePos(0));
 629          fm1.next_line(BytePos(22));
 630          fm2.next_line(BytePos(40));
 631          fm2.next_line(BytePos(58));
 632  
 633          fm1.record_multibyte_char(BytePos(3), 3);
 634          fm1.record_multibyte_char(BytePos(9), 3);
 635          fm1.record_multibyte_char(BytePos(12), 3);
 636          fm1.record_multibyte_char(BytePos(15), 3);
 637          fm1.record_multibyte_char(BytePos(18), 3);
 638          fm2.record_multibyte_char(BytePos(50), 3);
 639          fm2.record_multibyte_char(BytePos(53), 3);
 640          fm2.record_multibyte_char(BytePos(58), 3);
 641  
 642          cm
 643      }
 644  
 645      #[test]
 646      fn t6() {
 647          // Test bytepos_to_file_charpos in the presence of multi-byte chars
 648          let cm = init_code_map_mbc();
 649  
 650          let cp1 = cm.bytepos_to_file_charpos(BytePos(3));
 651          assert_eq!(cp1, CharPos(3));
 652  
 653          let cp2 = cm.bytepos_to_file_charpos(BytePos(6));
 654          assert_eq!(cp2, CharPos(4));
 655  
 656          let cp3 = cm.bytepos_to_file_charpos(BytePos(56));
 657          assert_eq!(cp3, CharPos(12));
 658  
 659          let cp4 = cm.bytepos_to_file_charpos(BytePos(61));
 660          assert_eq!(cp4, CharPos(15));
 661      }
 662  
 663      #[test]
 664      fn t7() {
 665          // Test span_to_lines for a span ending at the end of filemap
 666          let cm = init_code_map();
 667          let span = Span {lo: BytePos(12), hi: BytePos(23), expn_info: None};
 668          let file_lines = cm.span_to_lines(span);
 669  
 670          assert_eq!(file_lines.file.name, "blork.rs".to_strbuf());
 671          assert_eq!(file_lines.lines.len(), 1);
 672          assert_eq!(*file_lines.lines.get(0), 1u);
 673      }
 674  
 675      #[test]
 676      fn t8() {
 677          // Test span_to_snippet for a span ending at the end of filemap
 678          let cm = init_code_map();
 679          let span = Span {lo: BytePos(12), hi: BytePos(23), expn_info: None};
 680          let snippet = cm.span_to_snippet(span);
 681  
 682          assert_eq!(snippet, Some("second line".to_strbuf()));
 683      }
 684  
 685      #[test]
 686      fn t9() {
 687          // Test span_to_str for a span ending at the end of filemap
 688          let cm = init_code_map();
 689          let span = Span {lo: BytePos(12), hi: BytePos(23), expn_info: None};
 690          let sstr =  cm.span_to_str(span);
 691  
 692          assert_eq!(sstr, "blork.rs:2:1: 2:12".to_strbuf());
 693      }
 694  }


libsyntax/codemap.rs:238:35-238:35 -struct- definition:
/// A single source in the CodeMap
pub struct FileMap {
    /// The name of the file that the source came from, source that doesn't
references:- 17
334:         let filemap = Rc::new(FileMap {
335:             name: filename,
--
415:     pub fn get_filemap(&self, filename: &str) -> Rc<FileMap> {
416:         for fm in self.files.borrow().iter() {
libsyntax/parse/mod.rs:
238: pub fn string_to_filemap(sess: &ParseSess, source: StrBuf, path: StrBuf)
239:                          -> Rc<FileMap> {
240:     sess.span_diagnostic.cm.new_filemap(path, source)
--
243: // given a filemap, produce a sequence of token-trees
244: pub fn filemap_to_tts(sess: &ParseSess, filemap: Rc<FileMap>)
245:     -> Vec<ast::TokenTree> {
libsyntax/parse/lexer.rs:
51:     pub curr: Option<char>,
52:     pub filemap: Rc<codemap::FileMap>,
53:     /* cached: */
--
73: pub fn new_low_level_string_reader<'a>(span_diagnostic: &'a SpanHandler,
74:                                        filemap: Rc<codemap::FileMap>)
75:                                        -> StringReader<'a> {
libsyntax/codemap.rs:
157:     /// Information about the original source
158:     pub file: Rc<FileMap>,
159:     /// The (1-based) line number


libsyntax/codemap.rs:28:1-28:1 -trait- definition:
pub trait Pos {
    fn from_uint(n: uint) -> Self;
    fn to_uint(&self) -> uint;
references:- 3
29: pub trait Pos {
30:     fn from_uint(n: uint) -> Self;
31:     fn to_uint(&self) -> uint;
--
48: impl Pos for BytePos {
49:     fn from_uint(n: uint) -> BytePos { BytePos(n as u32) }
--
65: impl Pos for CharPos {
66:     fn from_uint(n: uint) -> CharPos { CharPos(n) }


libsyntax/codemap.rs:188:31-188:31 -struct- definition:
pub struct NameAndSpan {
    /// The name of the macro that was invoked to create the thing
    /// with this Span.
references:- 17
189: pub struct NameAndSpan {
libsyntax/ext/expand.rs:
271:                     call_site: attr.span,
272:                     callee: NameAndSpan {
273:                         name: mname.get().to_strbuf(),
--
335:                     call_site: attr.span,
336:                     callee: NameAndSpan {
337:                         name: mname.get().to_strbuf(),
--
579:                 call_site: s.span,
580:                 callee: NameAndSpan {
581:                     name: extnamestr.get().to_strbuf(),
libsyntax/ext/deriving/generic.rs:
988:             call_site: to_set,
989:             callee: codemap::NameAndSpan {
990:                 name: format!("deriving({})", trait_name).to_strbuf(),
libsyntax/codemap.rs:
189: pub struct NameAndSpan {
libsyntax/ext/source_util.rs:
160:                         ExpnInfo {
161:                             callee: NameAndSpan { name: ref name, .. },
162:                             ..
libsyntax/codemap.rs:
219:     /// foo { ... }`.
220:     pub callee: NameAndSpan
221: }


libsyntax/codemap.rs:298:1-298:1 -struct- definition:
pub struct CodeMap {
    pub files: RefCell<Vec<Rc<FileMap>>>
}
references:- 18
304:     pub fn new() -> CodeMap {
305:         CodeMap {
306:             files: RefCell::new(Vec::new()),
libsyntax/print/pprust.rs:
96: // copy forward.
97: pub fn print_crate<'a>(cm: &'a CodeMap,
98:                        span_diagnostic: &diagnostic::SpanHandler,
libsyntax/ext/base.rs:
413:     pub fn codemap(&self) -> &'a CodeMap { &self.parse_sess.span_diagnostic.cm }
414:     pub fn parse_sess(&self) -> &'a parse::ParseSess { self.parse_sess }
libsyntax/diagnostic.rs:
312: fn emit(dst: &mut EmitterWriter, cm: &codemap::CodeMap, rsp: RenderSpan,
313:         msg: &str, lvl: Level, custom: bool) -> io::IoResult<()> {
--
450: fn print_macro_backtrace(w: &mut EmitterWriter,
451:                          cm: &codemap::CodeMap,
452:                          sp: Span)
libsyntax/print/pprust.rs:
58:     pub s: pp::Printer,
59:     cm: Option<&'a CodeMap>,
60:     intr: Rc<token::IdentInterner>,


libsyntax/codemap.rs:222:1-222:1 -NK_AS_STR_TODO- definition:
pub type FileName = StrBuf;
pub struct FileLines {
    pub file: Rc<FileMap>,
references:- 4
242:     /// e.g. `<anon>`
243:     pub name: FileName,
244:     /// The complete source code
--
310:     pub fn new_filemap(&self, filename: FileName, src: StrBuf) -> Rc<FileMap> {
311:         let mut files = self.files.borrow_mut();
--
385:     pub fn span_to_filename(&self, sp: Span) -> FileName {
386:         self.lookup_char_pos(sp.lo).file.name.to_strbuf()


libsyntax/codemap.rs:180:31-180:31 -enum- definition:
pub enum MacroFormat {
    /// e.g. #[deriving(...)] <item>
    MacroAttribute,
references:- 5
179: /// The syntax with which a macro was invoked.
181: pub enum MacroFormat {
--
193:     /// The format with which the macro was invoked.
194:     pub format: MacroFormat,
195:     /// The span of the macro definition itself. The macro may not


libsyntax/codemap.rs:139:49-139:49 -fn- definition:
/* assuming that we're not in macro expansion */
pub fn mk_sp(lo: BytePos, hi: BytePos) -> Span {
    Span {lo: lo, hi: hi, expn_info: None}
references:- 52
libsyntax/parse/lexer.rs:
libsyntax/parse/parser.rs:
libsyntax/parse/attr.rs:
libsyntax/ext/tt/macro_parser.rs:
libsyntax/parse/parser.rs:


libsyntax/codemap.rs:42:33-42:33 -struct- definition:
pub struct CharPos(pub uint);
// FIXME: Lots of boilerplate in these impls, but so far my attempts to fix
// have been unsuccessful
references:- 28
41: /// values to CharPos values as necessary.
43: pub struct CharPos(pub uint);
--
70: impl Add<CharPos,CharPos> for CharPos {
71:     fn add(&self, rhs: &CharPos) -> CharPos {
--
76: impl Sub<CharPos,CharPos> for CharPos {
77:     fn sub(&self, rhs: &CharPos) -> CharPos {
78:         CharPos(self.to_uint() - rhs.to_uint())
--
502:     // Converts an absolute BytePos to a CharPos relative to the filemap.
503:     fn bytepos_to_file_charpos(&self, bpos: BytePos) -> CharPos {
504:         debug!("codemap: converting {:?} to char pos", bpos);
libsyntax/parse/lexer.rs:
48:     // The column of the next character to read
49:     pub col: CharPos,
50:     // The last character to be read
libsyntax/parse/comments.rs:
244: fn trim_whitespace_prefix_and_push_line(lines: &mut Vec<StrBuf> ,
245:                                         s: StrBuf, col: CharPos) {
246:     let len = s.len();
libsyntax/codemap.rs:
65: impl Pos for CharPos {
66:     fn from_uint(n: uint) -> CharPos { CharPos(n) }


libsyntax/codemap.rs:126:1-126:1 -fn- definition:
pub fn spanned<T>(lo: BytePos, hi: BytePos, t: T) -> Spanned<T> {
    respan(mk_sp(lo, hi), t)
}
references:- 33
libsyntax/parse/parser.rs:
libsyntax/parse/attr.rs:
libsyntax/attr.rs:
libsyntax/parse/parser.rs:


libsyntax/codemap.rs:224:1-224:1 -struct- definition:
pub struct FileLines {
    pub file: Rc<FileMap>,
    pub lines: Vec<uint>
references:- 4
395:         };
396:         FileLines {file: lo.file, lines: lines}
397:     }
libsyntax/diagnostic.rs:
416:                           lvl: Level,
417:                           lines: codemap::FileLines)
418:                           -> io::IoResult<()> {
libsyntax/codemap.rs:
389:     pub fn span_to_lines(&self, sp: Span) -> FileLines {
390:         let lo = self.lookup_char_pos(sp.lo);


libsyntax/codemap.rs:88:31-88:31 -struct- definition:
pub struct Span {
    pub lo: BytePos,
    pub hi: BytePos,
references:- 452
libsyntax/parse/parser.rs:
libsyntax/ext/base.rs:
libsyntax/ext/expand.rs:
libsyntax/codemap.rs:
libsyntax/ast.rs:
libsyntax/diagnostic.rs:
libsyntax/ast.rs:
libsyntax/ast_util.rs:
libsyntax/ast_map.rs:
libsyntax/visit.rs:
libsyntax/fold.rs:
libsyntax/parse/mod.rs:
libsyntax/parse/lexer.rs:
libsyntax/parse/parser.rs:
libsyntax/parse/obsolete.rs:
libsyntax/print/pprust.rs:
libsyntax/ext/asm.rs:
libsyntax/ext/base.rs:
libsyntax/ext/expand.rs:
libsyntax/ext/registrar.rs:
libsyntax/ext/quote.rs:
libsyntax/ext/deriving/mod.rs:
libsyntax/ext/deriving/bounds.rs:
libsyntax/ext/deriving/clone.rs:
libsyntax/ext/deriving/encodable.rs:
libsyntax/ext/deriving/decodable.rs:
libsyntax/ext/deriving/hash.rs:
libsyntax/ext/deriving/rand.rs:
libsyntax/ext/deriving/show.rs:
libsyntax/ext/deriving/zero.rs:
libsyntax/ext/deriving/default.rs:
libsyntax/ext/deriving/primitive.rs:
libsyntax/ext/deriving/cmp/eq.rs:
libsyntax/ext/deriving/cmp/totaleq.rs:
libsyntax/ext/deriving/cmp/ord.rs:
libsyntax/ext/deriving/cmp/totalord.rs:
libsyntax/ext/deriving/generic.rs:
libsyntax/ext/deriving/ty.rs:
libsyntax/ext/build.rs:
libsyntax/ext/tt/transcribe.rs:
libsyntax/ext/tt/macro_parser.rs:
libsyntax/ext/tt/macro_rules.rs:
libsyntax/ext/cfg.rs:
libsyntax/ext/fmt.rs:
libsyntax/ext/format.rs:
libsyntax/ext/env.rs:
libsyntax/ext/bytes.rs:
libsyntax/ext/concat.rs:
libsyntax/ext/concat_idents.rs:
libsyntax/ext/log_syntax.rs:
libsyntax/ext/source_util.rs:
libsyntax/ext/trace_macros.rs:
libsyntax/attr.rs:
libsyntax/diagnostic.rs:
libsyntax/ext/deriving/generic.rs:


libsyntax/codemap.rs:176:66-176:66 -struct- definition:
pub struct FileMapAndLine { pub fm: Rc<FileMap>, pub line: uint }
pub struct FileMapAndBytePos { pub fm: Rc<FileMap>, pub pos: BytePos }
/// The syntax with which a macro was invoked.
references:- 2
495:     fn lookup_byte_offset(&self, bpos: BytePos) -> FileMapAndBytePos {
496:         let idx = self.lookup_filemap_idx(bpos);
--
498:         let offset = bpos - fm.start_pos;
499:         FileMapAndBytePos {fm: fm, pos: offset}
500:     }


libsyntax/codemap.rs:230:64-230:64 -struct- definition:
/// Identifies an offset of a multi-byte character in a FileMap
pub struct MultiByteChar {
    /// The absolute offset of the character in the CodeMap
references:- 2
250:     /// Locations of multi-byte characters in the source code
251:     pub multibyte_chars: RefCell<Vec<MultiByteChar> >,
252: }
--
285:         assert!(bytes >=2 && bytes <= 4);
286:         let mbc = MultiByteChar {
287:             pos: pos,


libsyntax/codemap.rs:99:60-99:60 -struct- definition:
pub struct Spanned<T> {
    pub node: T,
    pub span: Span,
references:- 72
libsyntax/fold.rs:
libsyntax/parse/parser.rs:
libsyntax/parse/attr.rs:
libsyntax/ext/expand.rs:
libsyntax/ext/build.rs:
libsyntax/ext/tt/macro_rules.rs:
libsyntax/codemap.rs:
libsyntax/attr.rs:
libsyntax/ast.rs:
libsyntax/parse/parser.rs:
libsyntax/print/pprust.rs:
libsyntax/ext/expand.rs:
libsyntax/ext/tt/macro_parser.rs:
libsyntax/ast.rs:


libsyntax/codemap.rs:202:24-202:24 -struct- definition:
pub struct ExpnInfo {
    /// The location of the actual macro invocation, e.g. `let x =
    /// foo!();`
references:- 22
libsyntax/ext/expand.rs:
269:             Some(&ItemDecorator(dec_fn)) => {
270:                 fld.cx.bt_push(ExpnInfo {
271:                     call_site: attr.span,
--
333:             Some(&ItemModifier(dec_fn)) => {
334:                 fld.cx.bt_push(ExpnInfo {
335:                     call_site: attr.span,
--
411:             }
412:             fld.cx.bt_push(ExpnInfo {
413:                 call_site: it.span,
--
577:         Some(&NormalTT(ref expandfun, exp_span)) => {
578:             fld.cx.bt_push(ExpnInfo {
579:                 call_site: s.span,
libsyntax/ext/deriving/generic.rs:
986:         };
987:         to_set.expn_info = Some(@codemap::ExpnInfo {
988:             call_site: to_set,
libsyntax/codemap.rs:
201: /// Extra information for tracking macro expansion of spans
203: pub struct ExpnInfo {
libsyntax/ext/base.rs:
433:         match ei {
434:             ExpnInfo {call_site: cs, callee: ref callee} => {
435:                 self.backtrace =
libsyntax/ext/expand.rs:
944: fn original_span(cx: &ExtCtxt) -> @codemap::ExpnInfo {
945:     let mut relevant_info = cx.backtrace();
libsyntax/ext/source_util.rs:
155:     match *expn_info {
156:         ExpnInfo { call_site: ref call_site, .. } => {
157:             match call_site.expn_info {
--
159:                     match *next_expn_info {
160:                         ExpnInfo {
161:                             callee: NameAndSpan { name: ref name, .. },
libsyntax/ext/base.rs:
435:                 self.backtrace =
436:                     Some(@ExpnInfo {
437:                         call_site: Span {lo: cs.lo, hi: cs.hi,


libsyntax/codemap.rs:36:49-36:49 -struct- definition:
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
references:- 85
libsyntax/parse/lexer.rs:
libsyntax/parse/parser.rs:
libsyntax/parse/comments.rs:
libsyntax/print/pprust.rs:
libsyntax/ext/tt/macro_parser.rs:
libsyntax/attr.rs:
libsyntax/codemap.rs:


libsyntax/codemap.rs:167:40-167:40 -struct- definition:
// perhaps they should just be removed.
pub struct LocWithOpt {
    pub filename: FileName,
references:- 2
361:         let loc = self.lookup_char_pos(pos);
362:         LocWithOpt {
363:             filename: loc.file.name.to_strbuf(),


libsyntax/codemap.rs:134:1-134:1 -fn- definition:
pub fn dummy_spanned<T>(t: T) -> Spanned<T> {
    respan(DUMMY_SP, t)
}
references:- 18
libsyntax/ext/quote.rs:
194:         fn to_source(&self) -> StrBuf {
195:             let lit = dummy_spanned(ast::LitUint(*self as u64, ast::TyU));
196:             pprust::lit_to_str(&lit)
--
208:         fn to_source(&self) -> StrBuf {
209:             let lit = dummy_spanned(ast::LitUint(*self as u64, ast::TyU16));
210:             pprust::lit_to_str(&lit)
--
215:         fn to_source(&self) -> StrBuf {
216:             let lit = dummy_spanned(ast::LitUint(*self as u64, ast::TyU32));
217:             pprust::lit_to_str(&lit)
libsyntax/attr.rs:
153: pub fn mk_word_item(name: InternedString) -> @MetaItem {
154:     @dummy_spanned(MetaWord(name))
155: }
--
157: pub fn mk_attr(item: @MetaItem) -> Attribute {
158:     dummy_spanned(Attribute_ {
159:         style: ast::AttrInner,
libsyntax/ext/quote.rs:
222:         fn to_source(&self) -> StrBuf {
223:             let lit = dummy_spanned(ast::LitUint(*self as u64, ast::TyU64));
224:             pprust::lit_to_str(&lit)


libsyntax/codemap.rs:130:1-130:1 -fn- definition:
pub fn respan<T>(sp: Span, t: T) -> Spanned<T> {
    Spanned {node: t, span: sp}
}
references:- 34
libsyntax/fold.rs:
libsyntax/parse/obsolete.rs:
libsyntax/ext/base.rs:
libsyntax/ext/deriving/generic.rs:
libsyntax/ext/deriving/ty.rs:
libsyntax/ext/build.rs:
libsyntax/ext/format.rs:
libsyntax/ext/build.rs:


libsyntax/codemap.rs:175:56-175:56 -struct- definition:
// used to be structural records. Better names, anyone?
pub struct FileMapAndLine { pub fm: Rc<FileMap>, pub line: uint }
pub struct FileMapAndBytePos { pub fm: Rc<FileMap>, pub pos: BytePos }
references:- 3
476:     fn lookup_pos(&self, pos: BytePos) -> Loc {
477:         let FileMapAndLine {fm: f, line: a} = self.lookup_line(pos);
478:         let line = a + 1u; // Line numbers start at 1


libsyntax/codemap.rs:155:52-155:52 -struct- definition:
/// A source code location used for error reporting
pub struct Loc {
    /// Information about the original source
references:- 3
487:         assert!(chpos >= linechpos);
488:         Loc {
489:             file: f,