From 3de366d282de6de5dd1d69c40ea32f98a051fc66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABtan=20Cassiers?= <gaetan.cassiers@gmail.com> Date: Wed, 1 Jul 2015 21:13:10 +0200 Subject: [PATCH] Format modules into separate files --- src/changes.rs | 4 ++ src/lib.rs | 5 -- src/visitor.rs | 96 +++++++++++++++++++++++++-- tests/source/mod-2.rs | 3 + tests/source/nestedmod/mod.rs | 12 ++++ tests/source/nestedmod/mod2a.rs | 4 ++ tests/source/nestedmod/mod2b.rs | 3 + tests/source/nestedmod/mod2c.rs | 3 + tests/source/nestedmod/submod2/a.rs | 6 ++ tests/source/nestedmod/submod2/mod.rs | 5 ++ tests/target/mod-2.rs | 3 + tests/target/nestedmod/mod.rs | 12 ++++ tests/target/nestedmod/mod2a.rs | 4 ++ tests/target/nestedmod/mod2b.rs | 3 + tests/target/nestedmod/mod2c.rs | 4 ++ tests/target/nestedmod/submod2/a.rs | 7 ++ tests/target/nestedmod/submod2/mod.rs | 5 ++ 17 files changed, 167 insertions(+), 12 deletions(-) create mode 100644 tests/source/mod-2.rs create mode 100644 tests/source/nestedmod/mod.rs create mode 100644 tests/source/nestedmod/mod2a.rs create mode 100644 tests/source/nestedmod/mod2b.rs create mode 100644 tests/source/nestedmod/mod2c.rs create mode 100644 tests/source/nestedmod/submod2/a.rs create mode 100644 tests/source/nestedmod/submod2/mod.rs create mode 100644 tests/target/mod-2.rs create mode 100644 tests/target/nestedmod/mod.rs create mode 100644 tests/target/nestedmod/mod2a.rs create mode 100644 tests/target/nestedmod/mod2b.rs create mode 100644 tests/target/nestedmod/mod2c.rs create mode 100644 tests/target/nestedmod/submod2/a.rs create mode 100644 tests/target/nestedmod/submod2/mod.rs diff --git a/src/changes.rs b/src/changes.rs index 7a16a5bca66..74ee088105c 100644 --- a/src/changes.rs +++ b/src/changes.rs @@ -213,6 +213,10 @@ impl<'a> ChangeSet<'a> { Ok(None) } + + pub fn is_changed(&self, filename: &str) -> bool { + self.file_map.get(filename).expect("Unknown filename").len != 0 + } } // Iterates over each file in the ChangSet. Yields the filename and the changed diff --git a/src/lib.rs b/src/lib.rs index e0e72f90e6e..252b3ad05b7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -167,11 +167,6 @@ impl fmt::Display for FormatReport { fn fmt_ast<'a>(krate: &ast::Crate, codemap: &'a CodeMap, config: &'a Config) -> ChangeSet<'a> { let mut visitor = FmtVisitor::from_codemap(codemap, config); visit::walk_crate(&mut visitor, krate); - let files = codemap.files.borrow(); - if let Some(last) = files.last() { - visitor.format_missing(last.end_pos); - } - visitor.changes } diff --git a/src/visitor.rs b/src/visitor.rs index df50f6cda27..ed5a5f5da1b 100644 --- a/src/visitor.rs +++ b/src/visitor.rs @@ -11,9 +11,13 @@ use syntax::ast; use syntax::codemap::{self, CodeMap, Span, BytePos}; use syntax::visit; +use syntax::parse::token; +use syntax::attr; +use std::path::PathBuf; use utils; use config::Config; +use comment::FindUncommented; use changes::ChangeSet; use rewrite::{Rewrite, RewriteContext}; @@ -197,7 +201,6 @@ impl<'a, 'v> visit::Visitor<'v> for FmtVisitor<'a> { visit::walk_item(self, item); } ast::Item_::ItemImpl(..) | - ast::Item_::ItemMod(_) | ast::Item_::ItemTrait(..) => { self.block_indent += self.config.tab_spaces; visit::walk_item(self, item); @@ -227,6 +230,10 @@ impl<'a, 'v> visit::Visitor<'v> for FmtVisitor<'a> { item.span); self.last_pos = item.span.hi; } + ast::Item_::ItemMod(ref module) => { + self.format_missing_with_indent(item.span.lo); + self.format_mod(module, item.span, item.ident, &item.attrs); + } _ => { visit::walk_item(self, item); } @@ -267,12 +274,9 @@ impl<'a, 'v> visit::Visitor<'v> for FmtVisitor<'a> { } fn visit_mod(&mut self, m: &'v ast::Mod, s: Span, _: ast::NodeId) { - // Only visit inline mods here. - if self.codemap.lookup_char_pos(s.lo).file.name != - self.codemap.lookup_char_pos(m.inner.lo).file.name { - return; - } - visit::walk_mod(self, m); + // This is only called for the root module + let filename = self.codemap.span_to_filename(s); + self.format_separate_mod(m, &filename); } } @@ -352,4 +356,82 @@ impl<'a> FmtVisitor<'a> { result } + + fn format_mod(&mut self, m: &ast::Mod, s: Span, ident: ast::Ident, attrs: &[ast::Attribute]) { + debug!("FmtVisitor::format_mod: ident: {:?}, span: {:?}", ident, s); + // Decide whether this is an inline mod or an external mod. + // There isn't any difference between inline and external mod in AST, + // so we use the trick of searching for an opening brace. + // We can't use the inner span of the mod since it is weird when it + // is empty (no items). + // FIXME Use the inner span once rust-lang/rust#26755 is fixed. + let open_brace = self.codemap.span_to_snippet(s).unwrap().find_uncommented("{"); + match open_brace { + None => { + debug!("FmtVisitor::format_mod: external mod"); + let file_path = self.module_file(ident, attrs, s); + let filename = file_path.to_str().unwrap(); + if self.changes.is_changed(filename) { + // The file has already been reformatted, do nothing + } else { + self.format_separate_mod(m, filename); + } + // TODO Should rewrite properly `mod X;` + } + Some(open_brace) => { + debug!("FmtVisitor::format_mod: internal mod"); + debug!("... open_brace: {}, str: {:?}", open_brace, self.codemap.span_to_snippet(s)); + // Format everything until opening brace + // TODO Shoud rewrite properly + self.format_missing(s.lo + BytePos(open_brace as u32)); + self.block_indent += self.config.tab_spaces; + visit::walk_mod(self, m); + debug!("... last_pos after: {:?}", self.last_pos); + self.block_indent -= self.config.tab_spaces; + } + } + self.format_missing(s.hi); + debug!("FmtVisitor::format_mod: exit"); + } + + /// Find the file corresponding to an external mod + /// Same algorithm as syntax::parse::eval_src_mod + fn module_file(&self, id: ast::Ident, outer_attrs: &[ast::Attribute], id_sp: Span) -> PathBuf { + // FIXME use libsyntax once rust-lang/rust#26750 is merged + let mut prefix = PathBuf::from(&self.codemap.span_to_filename(id_sp)); + prefix.pop(); + let mod_string = token::get_ident(id); + match attr::first_attr_value_str_by_name(outer_attrs, "path") { + Some(d) => prefix.join(&*d), + None => { + let default_path_str = format!("{}.rs", mod_string); + let secondary_path_str = format!("{}/mod.rs", mod_string); + let default_path = prefix.join(&default_path_str); + let secondary_path = prefix.join(&secondary_path_str); + let default_exists = self.codemap.file_exists(&default_path); + let secondary_exists = self.codemap.file_exists(&secondary_path); + if default_exists { + default_path + } else if secondary_exists { + secondary_path + } else { + // Should never appens since rustc parsed everything sucessfully + panic!("Didn't found module {}", mod_string); + } + } + } + } + + /// Format the content of a module into a separate file + fn format_separate_mod(&mut self, m: &ast::Mod, filename: &str) { + let last_pos = self.last_pos; + let block_indent = self.block_indent; + let filemap = self.codemap.get_filemap(filename); + self.last_pos = filemap.start_pos; + self.block_indent = 0; + visit::walk_mod(self, m); + self.format_missing(filemap.end_pos); + self.last_pos = last_pos; + self.block_indent = block_indent; + } } diff --git a/tests/source/mod-2.rs b/tests/source/mod-2.rs new file mode 100644 index 00000000000..75b560ce93f --- /dev/null +++ b/tests/source/mod-2.rs @@ -0,0 +1,3 @@ +// Some nested mods + +mod nestedmod; diff --git a/tests/source/nestedmod/mod.rs b/tests/source/nestedmod/mod.rs new file mode 100644 index 00000000000..23dfa444257 --- /dev/null +++ b/tests/source/nestedmod/mod.rs @@ -0,0 +1,12 @@ + +mod mod2a; +mod mod2b; + +mod mymod1 { + use mod2a::{Foo,Bar}; +} + +#[path="mod2c.rs"] +mod mymod2; + +mod submod2; diff --git a/tests/source/nestedmod/mod2a.rs b/tests/source/nestedmod/mod2a.rs new file mode 100644 index 00000000000..5df457a8316 --- /dev/null +++ b/tests/source/nestedmod/mod2a.rs @@ -0,0 +1,4 @@ +// This is an empty file containing only +// comments + +// ................... diff --git a/tests/source/nestedmod/mod2b.rs b/tests/source/nestedmod/mod2b.rs new file mode 100644 index 00000000000..f128e2da6db --- /dev/null +++ b/tests/source/nestedmod/mod2b.rs @@ -0,0 +1,3 @@ + +#[path="mod2a.rs"] +mod c; diff --git a/tests/source/nestedmod/mod2c.rs b/tests/source/nestedmod/mod2c.rs new file mode 100644 index 00000000000..eda6b233e4b --- /dev/null +++ b/tests/source/nestedmod/mod2c.rs @@ -0,0 +1,3 @@ +// A standard mod + +fn a( ) {} diff --git a/tests/source/nestedmod/submod2/a.rs b/tests/source/nestedmod/submod2/a.rs new file mode 100644 index 00000000000..0eaf08f0d2c --- /dev/null +++ b/tests/source/nestedmod/submod2/a.rs @@ -0,0 +1,6 @@ +// Yet Another mod +// Nested + +use c::a; + +fn foo( ) { } diff --git a/tests/source/nestedmod/submod2/mod.rs b/tests/source/nestedmod/submod2/mod.rs new file mode 100644 index 00000000000..52f8be91022 --- /dev/null +++ b/tests/source/nestedmod/submod2/mod.rs @@ -0,0 +1,5 @@ +// Another mod + +mod a; + +use a::a; diff --git a/tests/target/mod-2.rs b/tests/target/mod-2.rs new file mode 100644 index 00000000000..75b560ce93f --- /dev/null +++ b/tests/target/mod-2.rs @@ -0,0 +1,3 @@ +// Some nested mods + +mod nestedmod; diff --git a/tests/target/nestedmod/mod.rs b/tests/target/nestedmod/mod.rs new file mode 100644 index 00000000000..be22f6d4037 --- /dev/null +++ b/tests/target/nestedmod/mod.rs @@ -0,0 +1,12 @@ + +mod mod2a; +mod mod2b; + +mod mymod1 { + use mod2a::{Foo, Bar}; +} + +#[path="mod2c.rs"] +mod mymod2; + +mod submod2; diff --git a/tests/target/nestedmod/mod2a.rs b/tests/target/nestedmod/mod2a.rs new file mode 100644 index 00000000000..5df457a8316 --- /dev/null +++ b/tests/target/nestedmod/mod2a.rs @@ -0,0 +1,4 @@ +// This is an empty file containing only +// comments + +// ................... diff --git a/tests/target/nestedmod/mod2b.rs b/tests/target/nestedmod/mod2b.rs new file mode 100644 index 00000000000..f128e2da6db --- /dev/null +++ b/tests/target/nestedmod/mod2b.rs @@ -0,0 +1,3 @@ + +#[path="mod2a.rs"] +mod c; diff --git a/tests/target/nestedmod/mod2c.rs b/tests/target/nestedmod/mod2c.rs new file mode 100644 index 00000000000..9027adeb212 --- /dev/null +++ b/tests/target/nestedmod/mod2c.rs @@ -0,0 +1,4 @@ +// A standard mod + +fn a() { +} diff --git a/tests/target/nestedmod/submod2/a.rs b/tests/target/nestedmod/submod2/a.rs new file mode 100644 index 00000000000..078a1d99f2c --- /dev/null +++ b/tests/target/nestedmod/submod2/a.rs @@ -0,0 +1,7 @@ +// Yet Another mod +// Nested + +use c::a; + +fn foo() { +} diff --git a/tests/target/nestedmod/submod2/mod.rs b/tests/target/nestedmod/submod2/mod.rs new file mode 100644 index 00000000000..52f8be91022 --- /dev/null +++ b/tests/target/nestedmod/submod2/mod.rs @@ -0,0 +1,5 @@ +// Another mod + +mod a; + +use a::a;