diff --git a/src/changes.rs b/src/changes.rs index ab5968dbf76..aba6eaa3250 100644 --- a/src/changes.rs +++ b/src/changes.rs @@ -216,10 +216,6 @@ fn write_system_newlines(mut writer: T, 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 93b66f45b56..b52ba9b7217 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -37,7 +37,6 @@ use syntax::ast; use syntax::codemap::CodeMap; use syntax::diagnostics; -use syntax::visit; use std::path::PathBuf; use std::collections::HashMap; @@ -64,6 +63,7 @@ mod rewrite; mod string; mod comment; +mod modules; const MIN_STRING: usize = 10; // When we get scoped annotations, we should have rustfmt::skip. @@ -198,7 +198,9 @@ fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { // 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); - visit::walk_crate(&mut visitor, krate); + for (path, module) in modules::list_modules(krate, codemap) { + visitor.format_separate_mod(module, path.to_str().unwrap()); + } visitor.changes } diff --git a/src/modules.rs b/src/modules.rs new file mode 100644 index 00000000000..04906c44e7a --- /dev/null +++ b/src/modules.rs @@ -0,0 +1,73 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use utils; + +use std::path::{Path, PathBuf}; +use std::collections::HashMap; + +use syntax::ast; +use syntax::codemap; +use syntax::parse::{parser, token}; + + +/// List all the files containing modules of a crate. +/// If a file is used twice in a crate, it appears only once. +pub fn list_modules<'a>(krate: &'a ast::Crate, + codemap: &codemap::CodeMap) + -> HashMap { + let mut result = HashMap::new(); + let root_filename: PathBuf = codemap.span_to_filename(krate.span).into(); + list_submodules(&krate.module, root_filename.parent().unwrap(), codemap, &mut result); + result.insert(root_filename, &krate.module); + result +} + +/// Recursively list all external modules included in a module. +fn list_submodules<'a>(module: &'a ast::Mod, + search_dir: &Path, + codemap: &codemap::CodeMap, + result: &mut HashMap) { + debug!("list_submodules: search_dir: {:?}", search_dir); + for item in module.items.iter() { + if let ast::ItemMod(ref sub_mod) = item.node { + if !utils::contains_skip(&item.attrs) { + 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) + } else { + let mod_path = module_file(item.ident, &item.attrs, search_dir, codemap); + let dir_path = mod_path.parent().unwrap().to_owned(); + result.insert(mod_path, sub_mod); + dir_path + }; + list_submodules(sub_mod, &dir_path, codemap, result); + } + } + } +} + +/// Find the file corresponding to an external mod +fn module_file(id: ast::Ident, + attrs: &[ast::Attribute], + dir_path: &Path, + codemap: &codemap::CodeMap) + -> PathBuf { + if let Some(path) = parser::Parser::submod_path_from_attr(attrs, &dir_path) { + return path; + } + + 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)) + } +} diff --git a/src/visitor.rs b/src/visitor.rs index f4ccfdd5c25..718a540fe94 100644 --- a/src/visitor.rs +++ b/src/visitor.rs @@ -11,8 +11,6 @@ use syntax::ast; use syntax::codemap::{self, CodeMap, Span, BytePos}; use syntax::visit; -use syntax::parse::parser; -use std::path::PathBuf; use utils; use config::Config; @@ -197,7 +195,7 @@ fn visit_item(&mut self, item: &'v ast::Item) { } ast::Item_::ItemMod(ref module) => { self.format_missing_with_indent(item.span.lo); - self.format_mod(module, item.span, item.ident, &item.attrs); + self.format_mod(module, item.span, item.ident); } _ => { visit::walk_item(self, item); @@ -237,12 +235,6 @@ fn visit_impl_item(&mut self, ii: &'v ast::ImplItem) { fn visit_mac(&mut self, mac: &'v ast::Mac) { visit::walk_mac(self, mac) } - - fn visit_mod(&mut self, m: &'v ast::Mod, s: Span, _: ast::NodeId) { - // This is only called for the root module - let filename = self.codemap.span_to_filename(s); - self.format_separate_mod(m, &filename); - } } impl<'a> FmtVisitor<'a> { @@ -322,7 +314,7 @@ pub fn rewrite_attrs(&self, attrs: &[ast::Attribute], indent: usize) -> String { result } - fn format_mod(&mut self, m: &ast::Mod, s: Span, ident: ast::Ident, attrs: &[ast::Attribute]) { + fn format_mod(&mut self, m: &ast::Mod, s: Span, ident: ast::Ident) { debug!("FmtVisitor::format_mod: ident: {:?}, span: {:?}", ident, s); // Decide whether this is an inline mod or an external mod. @@ -337,49 +329,15 @@ fn format_mod(&mut self, m: &ast::Mod, s: Span, ident: ast::Ident, attrs: &[ast: visit::walk_mod(self, m); debug!("... last_pos after: {:?}", self.last_pos); self.block_indent -= self.config.tab_spaces; - } else { - debug!("FmtVisitor::format_mod: external mod"); - let file_path = self.module_file(ident, attrs, local_file_name); - 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); - } - } - - debug!("FmtVisitor::format_mod: exit"); - } - - /// Find the file corresponding to an external mod - fn module_file(&self, id: ast::Ident, attrs: &[ast::Attribute], filename: String) -> PathBuf { - let dir_path = { - let mut path = PathBuf::from(&filename); - path.pop(); - path - }; - - if let Some(path) = parser::Parser::submod_path_from_attr(attrs, &dir_path) { - return path; - } - - match parser::Parser::default_submod_path(id, &dir_path, &self.codemap).result { - Ok(parser::ModulePathSuccess { path, .. }) => path, - _ => panic!("Couldn't find module {}", id) } } - /// 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; + pub fn format_separate_mod(&mut self, m: &ast::Mod, filename: &str) { 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; } fn format_import(&mut self, vis: ast::Visibility, vp: &ast::ViewPath, span: Span) { diff --git a/tests/source/nestedmod/mod.rs b/tests/source/nestedmod/mod.rs index 23dfa444257..d04e49570a4 100644 --- a/tests/source/nestedmod/mod.rs +++ b/tests/source/nestedmod/mod.rs @@ -4,6 +4,7 @@ mod mymod1 { use mod2a::{Foo,Bar}; +mod mod3a; } #[path="mod2c.rs"] diff --git a/tests/source/nestedmod/mymod1/mod3a.rs b/tests/source/nestedmod/mymod1/mod3a.rs new file mode 100644 index 00000000000..f28bde5e56d --- /dev/null +++ b/tests/source/nestedmod/mymod1/mod3a.rs @@ -0,0 +1,2 @@ +// Another mod +fn a( ) { } diff --git a/tests/target/nestedmod/mod.rs b/tests/target/nestedmod/mod.rs index be22f6d4037..b3456bf0d0f 100644 --- a/tests/target/nestedmod/mod.rs +++ b/tests/target/nestedmod/mod.rs @@ -4,6 +4,7 @@ mod mymod1 { use mod2a::{Foo, Bar}; + mod mod3a; } #[path="mod2c.rs"] diff --git a/tests/target/nestedmod/mymod1/mod3a.rs b/tests/target/nestedmod/mymod1/mod3a.rs new file mode 100644 index 00000000000..a6399f5565d --- /dev/null +++ b/tests/target/nestedmod/mymod1/mod3a.rs @@ -0,0 +1,3 @@ +// Another mod +fn a() { +}