diff --git a/src/changes.rs b/src/changes.rs index aba6eaa3250..ab758f71d95 100644 --- a/src/changes.rs +++ b/src/changes.rs @@ -15,96 +15,23 @@ use strings::string_buffer::StringBuffer; use std::collections::HashMap; -use syntax::codemap::{CodeMap, Span, BytePos}; use std::fmt; use std::fs::File; use std::io::{Write, stdout}; use WriteMode; use NewlineStyle; use config::Config; -use utils::round_up_to_power_of_two; // This is basically a wrapper around a bunch of Ropes which makes it convenient // to work with libsyntax. It is badly named. -pub struct ChangeSet<'a> { - file_map: HashMap, - codemap: &'a CodeMap, - file_spans: Vec<(u32, u32)>, +pub struct ChangeSet { + pub file_map: HashMap, } -impl<'a> ChangeSet<'a> { +impl ChangeSet { // Create a new ChangeSet for a given libsyntax CodeMap. - pub fn from_codemap(codemap: &'a CodeMap) -> ChangeSet<'a> { - let mut result = ChangeSet { - file_map: HashMap::new(), - codemap: codemap, - file_spans: Vec::with_capacity(codemap.files.borrow().len()), - }; - - for f in codemap.files.borrow().iter() { - // Use the length of the file as a heuristic for how much space we - // need. Round to the next power of two. - let buffer_cap = round_up_to_power_of_two(f.src.as_ref().unwrap().len()); - - result.file_map.insert(f.name.clone(), StringBuffer::with_capacity(buffer_cap)); - result.file_spans.push((f.start_pos.0, f.end_pos.0)); - } - - result.file_spans.sort(); - - result - } - - pub fn filespans_for_span(&self, start: BytePos, end: BytePos) -> Vec<(u32, u32)> { - assert!(start.0 <= end.0); - - if self.file_spans.len() == 0 { - return Vec::new(); - } - - // idx is the index into file_spans which indicates the current file, we - // with the file start denotes. - let mut idx = match self.file_spans.binary_search(&(start.0, ::std::u32::MAX)) { - Ok(i) => i, - Err(0) => 0, - Err(i) => i - 1, - }; - - let mut result = Vec::new(); - let mut start = start.0; - loop { - let cur_file = &self.file_spans[idx]; - idx += 1; - - if idx >= self.file_spans.len() || start >= end.0 { - if start < end.0 { - result.push((start, end.0)); - } - return result; - } - - let end = ::std::cmp::min(cur_file.1 - 1, end.0); - if start < end { - result.push((start, end)); - } - start = self.file_spans[idx].0; - } - } - - pub fn push_str(&mut self, filename: &str, text: &str) { - let buf = self.file_map.get_mut(&*filename).unwrap(); - buf.push_str(text) - } - - pub fn push_str_span(&mut self, span: Span, text: &str) { - let file_name = self.codemap.span_to_filename(span); - self.push_str(&file_name, text) - } - - // Fetch the output buffer for the given file name. - // Panics on unknown files. - pub fn get(&mut self, file_name: &str) -> &StringBuffer { - self.file_map.get(file_name).unwrap() + pub fn new() -> ChangeSet { + ChangeSet { file_map: HashMap::new() } } // Fetch a mutable reference to the output buffer for the given file name. @@ -113,17 +40,8 @@ impl<'a> ChangeSet<'a> { self.file_map.get_mut(file_name).unwrap() } - pub fn cur_offset(&mut self, filename: &str) -> usize { - self.file_map[&*filename].cur_offset() - } - - pub fn cur_offset_span(&mut self, span: Span) -> usize { - let filename = self.codemap.span_to_filename(span); - self.cur_offset(&filename) - } - // Return an iterator over the entire changed text. - pub fn text<'c>(&'c self) -> FileIterator<'c, 'a> { + pub fn text<'c>(&'c self) -> FileIterator<'c> { FileIterator { change_set: self, keys: self.file_map.keys().collect(), cur_key: 0 } } @@ -220,13 +138,13 @@ impl<'a> ChangeSet<'a> { // Iterates over each file in the ChangSet. Yields the filename and the changed // text for that file. -pub struct FileIterator<'c, 'a: 'c> { - change_set: &'c ChangeSet<'a>, +pub struct FileIterator<'c> { + change_set: &'c ChangeSet, keys: Vec<&'c String>, cur_key: usize, } -impl<'c, 'a> Iterator for FileIterator<'c, 'a> { +impl<'c> Iterator for FileIterator<'c> { type Item = (&'c str, &'c StringBuffer); fn next(&mut self) -> Option<(&'c str, &'c StringBuffer)> { @@ -240,7 +158,7 @@ impl<'c, 'a> Iterator for FileIterator<'c, 'a> { } } -impl<'a> fmt::Display for ChangeSet<'a> { +impl fmt::Display for ChangeSet { // Prints the entire changed text. fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { for (f, r) in self.text() { diff --git a/src/expr.rs b/src/expr.rs index b8c37dcab4c..334c509c59d 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -138,13 +138,9 @@ impl Rewrite for ast::Block { // Push text between last block item and end of block let snippet = visitor.snippet(mk_sp(visitor.last_pos, self.span.hi)); - visitor.changes.push_str_span(self.span, &snippet); + visitor.buffer.push_str(&snippet); - // Stringify visitor - let file_name = context.codemap.span_to_filename(self.span); - let string_buffer = visitor.changes.get(&file_name); - - Some(format!("{}{}", prefix, string_buffer)) + Some(format!("{}{}", prefix, visitor.buffer)) } } diff --git a/src/items.rs b/src/items.rs index eb727a20a56..378d822d413 100644 --- a/src/items.rs +++ b/src/items.rs @@ -382,7 +382,7 @@ impl<'a> FmtVisitor<'a> { generics: &ast::Generics, span: Span) { let header_str = self.format_header("enum ", ident, vis); - self.changes.push_str_span(span, &header_str); + self.buffer.push_str(&header_str); let enum_snippet = self.snippet(span); let body_start = span.lo + BytePos(enum_snippet.find_uncommented("{").unwrap() as u32 + 1); @@ -391,7 +391,7 @@ impl<'a> FmtVisitor<'a> { self.block_indent + self.config.tab_spaces, codemap::mk_sp(span.lo, body_start)); - self.changes.push_str_span(span, &generics_str); + self.buffer.push_str(&generics_str); self.last_pos = body_start; self.block_indent += self.config.tab_spaces; @@ -407,7 +407,7 @@ impl<'a> FmtVisitor<'a> { self.block_indent -= self.config.tab_spaces; self.format_missing_with_indent(span.lo + BytePos(enum_snippet.rfind('}').unwrap() as u32)); - self.changes.push_str_span(span, "}"); + self.buffer.push_str("}"); } // Variant of an enum @@ -421,9 +421,9 @@ impl<'a> FmtVisitor<'a> { let result = match field.node.kind { ast::VariantKind::TupleVariantKind(ref types) => { let vis = format_visibility(field.node.vis); - self.changes.push_str_span(field.span, vis); + self.buffer.push_str(vis); let name = field.node.name.to_string(); - self.changes.push_str_span(field.span, &name); + self.buffer.push_str(&name); let mut result = String::new(); @@ -491,10 +491,10 @@ impl<'a> FmtVisitor<'a> { self.block_indent) } }; - self.changes.push_str_span(field.span, &result); + self.buffer.push_str(&result); if !last_field || self.config.enum_trailing_comma { - self.changes.push_str_span(field.span, ","); + self.buffer.push_str(","); } self.last_pos = field.span.hi + BytePos(1); @@ -621,7 +621,7 @@ impl<'a> FmtVisitor<'a> { Some(generics), span, indent); - self.changes.push_str_span(span, &result); + self.buffer.push_str(&result); self.last_pos = span.hi; } diff --git a/src/lib.rs b/src/lib.rs index b52ba9b7217..f25e323504e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -196,12 +196,15 @@ impl fmt::Display for FormatReport { } // Formatting which depends on the AST. -fn fmt_ast<'a>(krate: &ast::Crate, codemap: &'a CodeMap, config: &'a Config) -> ChangeSet<'a> { - let mut visitor = FmtVisitor::from_codemap(codemap, config); +fn fmt_ast(krate: &ast::Crate, codemap: &CodeMap, config: &Config) -> ChangeSet { + let mut changes = ChangeSet::new(); for (path, module) in modules::list_modules(krate, codemap) { - visitor.format_separate_mod(module, path.to_str().unwrap()); + let path = path.to_str().unwrap(); + let mut visitor = FmtVisitor::from_codemap(codemap, config); + visitor.format_separate_mod(module, path); + changes.file_map.insert(path.to_owned(), visitor.buffer); } - visitor.changes + changes } // Formatting done on a char by char or line by line basis. diff --git a/src/missed_spans.rs b/src/missed_spans.rs index d560b3f2027..2f1a014a6e8 100644 --- a/src/missed_spans.rs +++ b/src/missed_spans.rs @@ -17,34 +17,33 @@ impl<'a> FmtVisitor<'a> { // TODO these format_missing methods are ugly. Refactor and add unit tests // for the central whitespace stripping loop. pub fn format_missing(&mut self, end: BytePos) { - self.format_missing_inner(end, |this, last_snippet, file_name, _| { - this.changes.push_str(file_name, last_snippet) + self.format_missing_inner(end, |this, last_snippet, _| { + this.buffer.push_str(last_snippet) }) } pub fn format_missing_with_indent(&mut self, end: BytePos) { - self.format_missing_inner(end, |this, last_snippet, file_name, snippet| { - this.changes.push_str(file_name, last_snippet.trim_right()); + self.format_missing_inner(end, |this, last_snippet, snippet| { + this.buffer.push_str(last_snippet.trim_right()); if last_snippet == snippet { // No new lines in the snippet. - this.changes.push_str(file_name, "\n"); + this.buffer.push_str("\n"); } let indent = make_indent(this.block_indent); - this.changes.push_str(file_name, &indent); + this.buffer.push_str(&indent); }) } - fn format_missing_inner(&mut self, - end: BytePos, - process_last_snippet: F) { + fn format_missing_inner(&mut self, + end: BytePos, + process_last_snippet: F) { let start = self.last_pos; debug!("format_missing_inner: {:?} to {:?}", self.codemap.lookup_char_pos(start), self.codemap.lookup_char_pos(end)); if start == end { - let file_name = &self.codemap.lookup_char_pos(start).file.name; - process_last_snippet(self, "", file_name, ""); + process_last_snippet(self, "", ""); return; } @@ -54,24 +53,18 @@ impl<'a> FmtVisitor<'a> { self.codemap.lookup_char_pos(end)); self.last_pos = end; - let spans = self.changes.filespans_for_span(start, end); - for (i, &(start, end)) in spans.iter().enumerate() { - let span = codemap::mk_sp(BytePos(start), BytePos(end)); - let file_name = &self.codemap.span_to_filename(span); - let snippet = self.snippet(span); + let span = codemap::mk_sp(start, end); + let snippet = self.snippet(span); - self.write_snippet(&snippet, - file_name, - i == spans.len() - 1, + self.write_snippet(&snippet, + true, &process_last_snippet); - } } - fn write_snippet(&mut self, - snippet: &str, - file_name: &str, - last_snippet: bool, - process_last_snippet: F) { + fn write_snippet(&mut self, + snippet: &str, + last_snippet: bool, + process_last_snippet: F) { // Trim whitespace from the right hand side of each line. // Annoyingly, the library functions for splitting by lines etc. are not // quite right, so we must do it ourselves. @@ -80,10 +73,10 @@ impl<'a> FmtVisitor<'a> { for (i, c) in snippet.char_indices() { if c == '\n' { if let Some(lw) = last_wspace { - self.changes.push_str(file_name, &snippet[line_start..lw]); - self.changes.push_str(file_name, "\n"); + self.buffer.push_str(&snippet[line_start..lw]); + self.buffer.push_str("\n"); } else { - self.changes.push_str(file_name, &snippet[line_start..i+1]); + self.buffer.push_str(&snippet[line_start..i+1]); } line_start = i + 1; @@ -99,9 +92,9 @@ impl<'a> FmtVisitor<'a> { } } if last_snippet { - process_last_snippet(self, &snippet[line_start..], file_name, snippet); + process_last_snippet(self, &snippet[line_start..], snippet); } else { - self.changes.push_str(file_name, &snippet[line_start..]); + self.buffer.push_str(&snippet[line_start..]); } } } diff --git a/src/modules.rs b/src/modules.rs index 04906c44e7a..6b3c223a4ff 100644 --- a/src/modules.rs +++ b/src/modules.rs @@ -15,7 +15,7 @@ use std::collections::HashMap; use syntax::ast; use syntax::codemap; -use syntax::parse::{parser, token}; +use syntax::parse::parser; /// List all the files containing modules of a crate. @@ -42,8 +42,7 @@ fn list_submodules<'a>(module: &'a ast::Mod, let is_internal = codemap.span_to_filename(item.span) == codemap.span_to_filename(sub_mod.inner); let dir_path = if is_internal { - let dir: &str = &token::get_ident(item.ident); - search_dir.join(dir) + search_dir.join(&item.ident.to_string()) } else { let mod_path = module_file(item.ident, &item.attrs, search_dir, codemap); let dir_path = mod_path.parent().unwrap().to_owned(); @@ -68,6 +67,6 @@ fn module_file(id: ast::Ident, match parser::Parser::default_submod_path(id, &dir_path, codemap).result { Ok(parser::ModulePathSuccess { path, .. }) => path, - Err(_) => panic!("Couldn't find module {}", token::get_ident(id)) + Err(_) => panic!("Couldn't find module {}", id) } } diff --git a/src/visitor.rs b/src/visitor.rs index 718a540fe94..23908edf8d0 100644 --- a/src/visitor.rs +++ b/src/visitor.rs @@ -12,15 +12,15 @@ use syntax::ast; use syntax::codemap::{self, CodeMap, Span, BytePos}; use syntax::visit; +use strings::string_buffer::StringBuffer; + use utils; use config::Config; - -use changes::ChangeSet; use rewrite::{Rewrite, RewriteContext}; pub struct FmtVisitor<'a> { pub codemap: &'a CodeMap, - pub changes: ChangeSet<'a>, + pub buffer: StringBuffer, pub last_pos: BytePos, // TODO RAII util for indenting pub block_indent: usize, @@ -33,7 +33,7 @@ impl<'a, 'v> visit::Visitor<'v> for FmtVisitor<'a> { self.codemap.lookup_char_pos(ex.span.lo), self.codemap.lookup_char_pos(ex.span.hi)); self.format_missing(ex.span.lo); - let offset = self.changes.cur_offset_span(ex.span); + let offset = self.buffer.cur_offset(); let context = RewriteContext { codemap: self.codemap, config: self.config, @@ -42,7 +42,7 @@ impl<'a, 'v> visit::Visitor<'v> for FmtVisitor<'a> { let rewrite = ex.rewrite(&context, self.config.max_width - offset, offset); if let Some(new_str) = rewrite { - self.changes.push_str_span(ex.span, &new_str); + self.buffer.push_str(&new_str); self.last_pos = ex.span.hi; } } @@ -72,7 +72,7 @@ impl<'a, 'v> visit::Visitor<'v> for FmtVisitor<'a> { self.codemap.lookup_char_pos(b.span.lo), self.codemap.lookup_char_pos(b.span.hi)); - self.changes.push_str_span(b.span, "{"); + self.buffer.push_str("{"); self.last_pos = self.last_pos + BytePos(1); self.block_indent += self.config.tab_spaces; @@ -91,7 +91,7 @@ impl<'a, 'v> visit::Visitor<'v> for FmtVisitor<'a> { self.block_indent -= self.config.tab_spaces; // TODO we should compress any newlines here to just one self.format_missing_with_indent(b.span.hi - BytePos(1)); - self.changes.push_str_span(b.span, "}"); + self.buffer.push_str("}"); self.last_pos = b.span.hi; } @@ -124,7 +124,7 @@ impl<'a, 'v> visit::Visitor<'v> for FmtVisitor<'a> { abi, vis, codemap::mk_sp(s.lo, b.span.lo)); - self.changes.push_str_span(s, &new_fn); + self.buffer.push_str(&new_fn); } visit::FkMethod(ident, ref sig, vis) => { let new_fn = self.rewrite_fn(indent, @@ -137,7 +137,7 @@ impl<'a, 'v> visit::Visitor<'v> for FmtVisitor<'a> { &sig.abi, vis.unwrap_or(ast::Visibility::Inherited), codemap::mk_sp(s.lo, b.span.lo)); - self.changes.push_str_span(s, &new_fn); + self.buffer.push_str(&new_fn); } visit::FkFnBlock(..) => {} } @@ -173,7 +173,7 @@ impl<'a, 'v> visit::Visitor<'v> for FmtVisitor<'a> { ast::Item_::ItemExternCrate(_) => { self.format_missing_with_indent(item.span.lo); let new_str = self.snippet(item.span); - self.changes.push_str_span(item.span, &new_str); + self.buffer.push_str(&new_str); self.last_pos = item.span.hi; } ast::Item_::ItemStruct(ref def, ref generics) => { @@ -217,7 +217,7 @@ impl<'a, 'v> visit::Visitor<'v> for FmtVisitor<'a> { sig, ti.span); - self.changes.push_str_span(ti.span, &new_fn); + self.buffer.push_str(&new_fn); self.last_pos = ti.span.hi; } // TODO format trait types @@ -241,7 +241,7 @@ impl<'a> FmtVisitor<'a> { pub fn from_codemap<'b>(codemap: &'b CodeMap, config: &'b Config) -> FmtVisitor<'b> { FmtVisitor { codemap: codemap, - changes: ChangeSet::from_codemap(codemap), + buffer: StringBuffer::new(), last_pos: BytePos(0), block_indent: 0, config: config, @@ -273,7 +273,7 @@ impl<'a> FmtVisitor<'a> { true } else { let rewrite = self.rewrite_attrs(attrs, self.block_indent); - self.changes.push_str_span(first.span, &rewrite); + self.buffer.push_str(&rewrite); let last = attrs.last().unwrap(); self.last_pos = last.span.hi; false @@ -363,7 +363,7 @@ impl<'a> FmtVisitor<'a> { Some(ref s) => { let s = format!("{}use {};", vis, s); self.format_missing_with_indent(span.lo); - self.changes.push_str_span(span, &s); + self.buffer.push_str(&s); self.last_pos = span.hi; } None => {