Skip to content

Commit 3de366d

Browse files
committed
Format modules into separate files
1 parent 83290f1 commit 3de366d

File tree

17 files changed

+167
-12
lines changed

17 files changed

+167
-12
lines changed

src/changes.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,10 @@ impl<'a> ChangeSet<'a> {
213213

214214
Ok(None)
215215
}
216+
217+
pub fn is_changed(&self, filename: &str) -> bool {
218+
self.file_map.get(filename).expect("Unknown filename").len != 0
219+
}
216220
}
217221

218222
// Iterates over each file in the ChangSet. Yields the filename and the changed

src/lib.rs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -167,11 +167,6 @@ impl fmt::Display for FormatReport {
167167
fn fmt_ast<'a>(krate: &ast::Crate, codemap: &'a CodeMap, config: &'a Config) -> ChangeSet<'a> {
168168
let mut visitor = FmtVisitor::from_codemap(codemap, config);
169169
visit::walk_crate(&mut visitor, krate);
170-
let files = codemap.files.borrow();
171-
if let Some(last) = files.last() {
172-
visitor.format_missing(last.end_pos);
173-
}
174-
175170
visitor.changes
176171
}
177172

src/visitor.rs

Lines changed: 89 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,13 @@
1111
use syntax::ast;
1212
use syntax::codemap::{self, CodeMap, Span, BytePos};
1313
use syntax::visit;
14+
use syntax::parse::token;
15+
use syntax::attr;
16+
use std::path::PathBuf;
1417

1518
use utils;
1619
use config::Config;
20+
use comment::FindUncommented;
1721

1822
use changes::ChangeSet;
1923
use rewrite::{Rewrite, RewriteContext};
@@ -197,7 +201,6 @@ impl<'a, 'v> visit::Visitor<'v> for FmtVisitor<'a> {
197201
visit::walk_item(self, item);
198202
}
199203
ast::Item_::ItemImpl(..) |
200-
ast::Item_::ItemMod(_) |
201204
ast::Item_::ItemTrait(..) => {
202205
self.block_indent += self.config.tab_spaces;
203206
visit::walk_item(self, item);
@@ -227,6 +230,10 @@ impl<'a, 'v> visit::Visitor<'v> for FmtVisitor<'a> {
227230
item.span);
228231
self.last_pos = item.span.hi;
229232
}
233+
ast::Item_::ItemMod(ref module) => {
234+
self.format_missing_with_indent(item.span.lo);
235+
self.format_mod(module, item.span, item.ident, &item.attrs);
236+
}
230237
_ => {
231238
visit::walk_item(self, item);
232239
}
@@ -267,12 +274,9 @@ impl<'a, 'v> visit::Visitor<'v> for FmtVisitor<'a> {
267274
}
268275

269276
fn visit_mod(&mut self, m: &'v ast::Mod, s: Span, _: ast::NodeId) {
270-
// Only visit inline mods here.
271-
if self.codemap.lookup_char_pos(s.lo).file.name !=
272-
self.codemap.lookup_char_pos(m.inner.lo).file.name {
273-
return;
274-
}
275-
visit::walk_mod(self, m);
277+
// This is only called for the root module
278+
let filename = self.codemap.span_to_filename(s);
279+
self.format_separate_mod(m, &filename);
276280
}
277281
}
278282

@@ -352,4 +356,82 @@ impl<'a> FmtVisitor<'a> {
352356

353357
result
354358
}
359+
360+
fn format_mod(&mut self, m: &ast::Mod, s: Span, ident: ast::Ident, attrs: &[ast::Attribute]) {
361+
debug!("FmtVisitor::format_mod: ident: {:?}, span: {:?}", ident, s);
362+
// Decide whether this is an inline mod or an external mod.
363+
// There isn't any difference between inline and external mod in AST,
364+
// so we use the trick of searching for an opening brace.
365+
// We can't use the inner span of the mod since it is weird when it
366+
// is empty (no items).
367+
// FIXME Use the inner span once rust-lang/rust#26755 is fixed.
368+
let open_brace = self.codemap.span_to_snippet(s).unwrap().find_uncommented("{");
369+
match open_brace {
370+
None => {
371+
debug!("FmtVisitor::format_mod: external mod");
372+
let file_path = self.module_file(ident, attrs, s);
373+
let filename = file_path.to_str().unwrap();
374+
if self.changes.is_changed(filename) {
375+
// The file has already been reformatted, do nothing
376+
} else {
377+
self.format_separate_mod(m, filename);
378+
}
379+
// TODO Should rewrite properly `mod X;`
380+
}
381+
Some(open_brace) => {
382+
debug!("FmtVisitor::format_mod: internal mod");
383+
debug!("... open_brace: {}, str: {:?}", open_brace, self.codemap.span_to_snippet(s));
384+
// Format everything until opening brace
385+
// TODO Shoud rewrite properly
386+
self.format_missing(s.lo + BytePos(open_brace as u32));
387+
self.block_indent += self.config.tab_spaces;
388+
visit::walk_mod(self, m);
389+
debug!("... last_pos after: {:?}", self.last_pos);
390+
self.block_indent -= self.config.tab_spaces;
391+
}
392+
}
393+
self.format_missing(s.hi);
394+
debug!("FmtVisitor::format_mod: exit");
395+
}
396+
397+
/// Find the file corresponding to an external mod
398+
/// Same algorithm as syntax::parse::eval_src_mod
399+
fn module_file(&self, id: ast::Ident, outer_attrs: &[ast::Attribute], id_sp: Span) -> PathBuf {
400+
// FIXME use libsyntax once rust-lang/rust#26750 is merged
401+
let mut prefix = PathBuf::from(&self.codemap.span_to_filename(id_sp));
402+
prefix.pop();
403+
let mod_string = token::get_ident(id);
404+
match attr::first_attr_value_str_by_name(outer_attrs, "path") {
405+
Some(d) => prefix.join(&*d),
406+
None => {
407+
let default_path_str = format!("{}.rs", mod_string);
408+
let secondary_path_str = format!("{}/mod.rs", mod_string);
409+
let default_path = prefix.join(&default_path_str);
410+
let secondary_path = prefix.join(&secondary_path_str);
411+
let default_exists = self.codemap.file_exists(&default_path);
412+
let secondary_exists = self.codemap.file_exists(&secondary_path);
413+
if default_exists {
414+
default_path
415+
} else if secondary_exists {
416+
secondary_path
417+
} else {
418+
// Should never appens since rustc parsed everything sucessfully
419+
panic!("Didn't found module {}", mod_string);
420+
}
421+
}
422+
}
423+
}
424+
425+
/// Format the content of a module into a separate file
426+
fn format_separate_mod(&mut self, m: &ast::Mod, filename: &str) {
427+
let last_pos = self.last_pos;
428+
let block_indent = self.block_indent;
429+
let filemap = self.codemap.get_filemap(filename);
430+
self.last_pos = filemap.start_pos;
431+
self.block_indent = 0;
432+
visit::walk_mod(self, m);
433+
self.format_missing(filemap.end_pos);
434+
self.last_pos = last_pos;
435+
self.block_indent = block_indent;
436+
}
355437
}

tests/source/mod-2.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
// Some nested mods
2+
3+
mod nestedmod;

tests/source/nestedmod/mod.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
2+
mod mod2a;
3+
mod mod2b;
4+
5+
mod mymod1 {
6+
use mod2a::{Foo,Bar};
7+
}
8+
9+
#[path="mod2c.rs"]
10+
mod mymod2;
11+
12+
mod submod2;

tests/source/nestedmod/mod2a.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// This is an empty file containing only
2+
// comments
3+
4+
// ...................

tests/source/nestedmod/mod2b.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
2+
#[path="mod2a.rs"]
3+
mod c;

tests/source/nestedmod/mod2c.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
// A standard mod
2+
3+
fn a( ) {}

tests/source/nestedmod/submod2/a.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// Yet Another mod
2+
// Nested
3+
4+
use c::a;
5+
6+
fn foo( ) { }

tests/source/nestedmod/submod2/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// Another mod
2+
3+
mod a;
4+
5+
use a::a;

tests/target/mod-2.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
// Some nested mods
2+
3+
mod nestedmod;

tests/target/nestedmod/mod.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
2+
mod mod2a;
3+
mod mod2b;
4+
5+
mod mymod1 {
6+
use mod2a::{Foo, Bar};
7+
}
8+
9+
#[path="mod2c.rs"]
10+
mod mymod2;
11+
12+
mod submod2;

tests/target/nestedmod/mod2a.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// This is an empty file containing only
2+
// comments
3+
4+
// ...................

tests/target/nestedmod/mod2b.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
2+
#[path="mod2a.rs"]
3+
mod c;

tests/target/nestedmod/mod2c.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// A standard mod
2+
3+
fn a() {
4+
}

tests/target/nestedmod/submod2/a.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// Yet Another mod
2+
// Nested
3+
4+
use c::a;
5+
6+
fn foo() {
7+
}

tests/target/nestedmod/submod2/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// Another mod
2+
3+
mod a;
4+
5+
use a::a;

0 commit comments

Comments
 (0)