diff --git a/src/changes.rs b/src/changes.rs index 7a16a5bca66..3f0d985da48 100644 --- a/src/changes.rs +++ b/src/changes.rs @@ -35,11 +35,9 @@ pub struct ChangeSet<'a> { impl<'a> ChangeSet<'a> { // 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()), - }; + 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 @@ -116,11 +114,7 @@ impl<'a> ChangeSet<'a> { // Return an iterator over the entire changed text. pub fn text<'c>(&'c self) -> FileIterator<'c, 'a> { - FileIterator { - change_set: self, - keys: self.file_map.keys().collect(), - cur_key: 0, - } + FileIterator { change_set: self, keys: self.file_map.keys().collect(), cur_key: 0 } } // Append a newline to the end of each file. @@ -153,12 +147,11 @@ impl<'a> ChangeSet<'a> { let text = &self.file_map[filename]; // prints all newlines either as `\n` or as `\r\n` - fn write_system_newlines( - mut writer: T, - text: &StringBuffer, - config: &Config) - -> Result<(), ::std::io::Error> - where T: Write, + fn write_system_newlines(mut writer: T, + text: &StringBuffer, + config: &Config) + -> Result<(), ::std::io::Error> + where T: Write { match config.newline_style { NewlineStyle::Unix => write!(writer, "{}", text), @@ -213,6 +206,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/comment.rs b/src/comment.rs index 1a16d349208..064cace6c51 100644 --- a/src/comment.rs +++ b/src/comment.rs @@ -24,15 +24,13 @@ pub fn rewrite_comment(orig: &str, block_style: bool, width: usize, offset: usiz let max_chars = width.checked_sub(closer.len()).unwrap_or(1) .checked_sub(opener.len()).unwrap_or(1); - let fmt = StringFormat { - opener: "", - closer: "", - line_start: line_start, - line_end: "", - width: max_chars, - offset: offset + opener.len() - line_start.len(), - trim_end: true - }; + let fmt = StringFormat { opener: "", + closer: "", + line_start: line_start, + line_end: "", + width: max_chars, + offset: offset + opener.len() - line_start.len(), + trim_end: true, }; let indent_str = make_indent(offset); let line_breaks = s.chars().filter(|&c| c == '\n').count(); @@ -102,8 +100,8 @@ fn format_comments() { let input = "// comment"; let expected_output = "/* com\n \ - * men\n \ - * t */"; + * men\n \ + * t */"; assert_eq!(expected_output, rewrite_comment(input, true, 9, 69)); assert_eq!("/* trimmed */", rewrite_comment("/* trimmed */", true, 100, 100)); diff --git a/src/expr.rs b/src/expr.rs index 6fff8be9fc7..da706c4afa7 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -63,7 +63,7 @@ fn rewrite_string_lit(context: &RewriteContext, span: Span, width: usize, offset: usize) - -> Option { + -> Option { // Check if there is anything to fix: we always try to fixup multi-line // strings, or if the string is too long for the line. let l_loc = context.codemap.lookup_char_pos(span.lo); @@ -71,15 +71,13 @@ fn rewrite_string_lit(context: &RewriteContext, if l_loc.line == r_loc.line && r_loc.col.to_usize() <= context.config.max_width { return context.codemap.span_to_snippet(span).ok(); } - let fmt = StringFormat { - opener: "\"", - closer: "\"", - line_start: " ", - line_end: "\\", - width: width, - offset: offset, - trim_end: false - }; + let fmt = StringFormat { opener: "\"", + closer: "\"", + line_start: " ", + line_end: "\\", + width: width, + offset: offset, + trim_end: false, }; Some(rewrite_string(&s.escape_default(), &fmt)) } @@ -90,7 +88,7 @@ fn rewrite_call(context: &RewriteContext, span: Span, width: usize, offset: usize) - -> Option { + -> Option { debug!("rewrite_call, width: {}, offset: {}", width, offset); // TODO using byte lens instead of char lens (and probably all over the place too) @@ -119,20 +117,22 @@ fn rewrite_call(context: &RewriteContext, callee.span.hi + BytePos(1), span.hi); - let fmt = ListFormatting { - tactic: ListTactic::HorizontalVertical, - separator: ",", - trailing_separator: SeparatorTactic::Never, - indent: offset, - h_width: remaining_width, - v_width: remaining_width, - ends_with_newline: true, - }; + let fmt = ListFormatting { tactic: ListTactic::HorizontalVertical, + separator: ",", + trailing_separator: SeparatorTactic::Never, + indent: offset, + h_width: remaining_width, + v_width: remaining_width, + ends_with_newline: true, }; Some(format!("{}({})", callee_str, write_list(&items, &fmt))) } -fn rewrite_paren(context: &RewriteContext, subexpr: &ast::Expr, width: usize, offset: usize) -> Option { +fn rewrite_paren(context: &RewriteContext, + subexpr: &ast::Expr, + width: usize, + offset: usize) + -> Option { debug!("rewrite_paren, width: {}, offset: {}", width, offset); // 1 is for opening paren, 2 is for opening+closing, we want to keep the closing // paren on the same line as the subexpr @@ -148,14 +148,13 @@ fn rewrite_struct_lit<'a>(context: &RewriteContext, span: Span, width: usize, offset: usize) - -> Option -{ + -> Option { debug!("rewrite_struct_lit: width {}, offset {}", width, offset); assert!(fields.len() > 0 || base.is_some()); enum StructLitField<'a> { Regular(&'a ast::Field), - Base(&'a ast::Expr) + Base(&'a ast::Expr), } let path_str = pprust::path_to_string(path); @@ -203,19 +202,17 @@ fn rewrite_struct_lit<'a>(context: &RewriteContext, span_after(span, "{", context.codemap), span.hi); - let fmt = ListFormatting { - tactic: ListTactic::HorizontalVertical, - separator: ",", - trailing_separator: if base.is_some() { + let fmt = ListFormatting { tactic: ListTactic::HorizontalVertical, + separator: ",", + trailing_separator: if base.is_some() { SeparatorTactic::Never } else { context.config.struct_lit_trailing_comma }, - indent: indent, - h_width: budget, - v_width: budget, - ends_with_newline: true, - }; + indent: indent, + h_width: budget, + v_width: budget, + ends_with_newline: true, }; let fields_str = write_list(&items, &fmt); Some(format!("{} {{ {} }}", path_str, fields_str)) @@ -225,7 +222,11 @@ fn rewrite_struct_lit<'a>(context: &RewriteContext, // } } -fn rewrite_field(context: &RewriteContext, field: &ast::Field, width: usize, offset: usize) -> Option { +fn rewrite_field(context: &RewriteContext, + field: &ast::Field, + width: usize, + offset: usize) + -> Option { let name = &token::get_ident(field.ident.node); let overhead = name.len() + 2; let expr = field.expr.rewrite(context, width - overhead, offset + overhead); @@ -262,15 +263,13 @@ fn rewrite_tuple_lit(context: &RewriteContext, SeparatorTactic::Never }; - let fmt = ListFormatting { - tactic: ListTactic::HorizontalVertical, - separator: ",", - trailing_separator: trailing_separator_tactic, - indent: indent, - h_width: width - 2, - v_width: width - 2, - ends_with_newline: true, - }; + let fmt = ListFormatting { tactic: ListTactic::HorizontalVertical, + separator: ",", + trailing_separator: trailing_separator_tactic, + indent: indent, + h_width: width - 2, + v_width: width - 2, + ends_with_newline: true, }; Some(format!("({})", write_list(&items, &fmt))) } diff --git a/src/imports.rs b/src/imports.rs index 535e409288b..d9eb7b772a3 100644 --- a/src/imports.rs +++ b/src/imports.rs @@ -48,7 +48,8 @@ impl<'a> FmtVisitor<'a> { path: &ast::Path, path_list: &[ast::PathListItem], visibility: ast::Visibility, - span: Span) -> Option { + span: Span) + -> Option { let path_str = pprust::path_to_string(path); let vis = format_visibility(visibility); @@ -70,18 +71,17 @@ impl<'a> FmtVisitor<'a> { let remaining_line_budget = one_line_budget.checked_sub(used_width).unwrap_or(0); let remaining_multi_budget = multi_line_budget.checked_sub(used_width).unwrap_or(0); - let fmt = ListFormatting { - tactic: ListTactic::Mixed, - separator: ",", - trailing_separator: SeparatorTactic::Never, - indent: block_indent + indent, - h_width: remaining_line_budget, - v_width: remaining_multi_budget, - ends_with_newline: true, - }; + let fmt = ListFormatting { tactic: ListTactic::Mixed, + separator: ",", + trailing_separator: SeparatorTactic::Never, + indent: block_indent + indent, + h_width: remaining_line_budget, + v_width: remaining_multi_budget, + ends_with_newline: true, }; let mut items = itemize_list(self.codemap, - vec![ListItem::from_str("")], // Dummy value, explanation below + vec![ListItem::from_str("")], /* Dummy value, explanation + * below */ path_list.iter(), ",", "}", diff --git a/src/issues.rs b/src/issues.rs index 0efe0c31c78..bb7e9ba14e3 100644 --- a/src/issues.rs +++ b/src/issues.rs @@ -21,7 +21,7 @@ static FIX_ME_CHARS: &'static [char] = &['F', 'I', 'X', 'M', 'E']; pub enum ReportTactic { Always, Unnumbered, - Never + Never, } impl ReportTactic { @@ -40,12 +40,12 @@ impl_enum_decodable!(ReportTactic, Always, Unnumbered, Never); enum Seeking { Issue { todo_idx: usize, - fixme_idx: usize + fixme_idx: usize, }, Number { issue: Issue, - part: NumberPart - } + part: NumberPart, + }, } #[derive(Clone, Copy)] @@ -53,7 +53,7 @@ enum NumberPart { OpenParen, Pound, Number, - CloseParen + CloseParen, } #[derive(PartialEq, Eq, Debug, Clone, Copy)] @@ -79,13 +79,13 @@ impl fmt::Display for Issue { #[derive(PartialEq, Eq, Debug, Clone, Copy)] enum IssueType { Todo, - Fixme + Fixme, } enum IssueClassification { Good, Bad(Issue), - None + None, } pub struct BadIssueSeeker { @@ -96,11 +96,9 @@ pub struct BadIssueSeeker { impl BadIssueSeeker { pub fn new(report_todo: ReportTactic, report_fixme: ReportTactic) -> BadIssueSeeker { - BadIssueSeeker { - state: Seeking::Issue { todo_idx: 0, fixme_idx: 0 }, - report_todo: report_todo, - report_fixme: report_fixme, - } + BadIssueSeeker { state: Seeking::Issue { todo_idx: 0, fixme_idx: 0 }, + report_todo: report_todo, + report_fixme: report_fixme, } } // Check whether or not the current char is conclusive evidence for an @@ -176,8 +174,7 @@ impl BadIssueSeeker { c: char, issue: Issue, mut part: NumberPart) - -> IssueClassification - { + -> IssueClassification { if ! issue.missing_number || c == '\n' { return IssueClassification::Bad(issue); } else if c == ')' { @@ -272,10 +269,7 @@ fn find_issue() { #[test] fn issue_type() { let mut seeker = BadIssueSeeker::new(ReportTactic::Always, ReportTactic::Never); - let expected = Some(Issue { - issue_type: IssueType::Todo, - missing_number: false - }); + let expected = Some(Issue { issue_type: IssueType::Todo, missing_number: false }); assert_eq!(expected, "TODO(#100): more awesomeness".chars() @@ -284,10 +278,7 @@ fn issue_type() { .unwrap()); let mut seeker = BadIssueSeeker::new(ReportTactic::Never, ReportTactic::Unnumbered); - let expected = Some(Issue { - issue_type: IssueType::Fixme, - missing_number: true - }); + let expected = Some(Issue { issue_type: IssueType::Fixme, missing_number: true }); assert_eq!(expected, "Test. FIXME: bad, bad, not good".chars() diff --git a/src/items.rs b/src/items.rs index 17941dcd242..0f7f44f8d99 100644 --- a/src/items.rs +++ b/src/items.rs @@ -11,7 +11,7 @@ // Formatting top-level items - functions, structs, enums, traits, impls. use {ReturnIndent, BraceStyle}; -use utils::{format_visibility, make_indent, contains_skip, span_after}; +use utils::{format_visibility, make_indent, contains_skip, span_after, end_typaram}; use lists::{write_list, itemize_list, ListItem, ListFormatting, SeparatorTactic, ListTactic}; use comment::FindUncommented; use visitor::FmtVisitor; @@ -33,8 +33,7 @@ impl<'a> FmtVisitor<'a> { abi: &abi::Abi, vis: ast::Visibility, span: Span) - -> String - { + -> String { let newline_brace = self.newline_for_brace(&generics.where_clause); let mut result = self.rewrite_fn_base(indent, @@ -67,8 +66,7 @@ impl<'a> FmtVisitor<'a> { ident: ast::Ident, sig: &ast::MethodSig, span: Span) - -> String - { + -> String { // Drop semicolon or it will be interpreted as comment let span = codemap::mk_sp(span.lo, span.hi - BytePos(1)); @@ -102,8 +100,7 @@ impl<'a> FmtVisitor<'a> { vis: ast::Visibility, span: Span, newline_brace: bool) - -> String - { + -> String { // FIXME we'll lose any comments in between parts of the function decl, but anyone // who comments there probably deserves what they get. @@ -160,13 +157,21 @@ impl<'a> FmtVisitor<'a> { result.push('('); } + // A conservative estimation, to goal is to be over all parens in generics + let args_start = generics.ty_params + .last() + .map(|tp| end_typaram(tp)) + .unwrap_or(span.lo); + let args_span = codemap::mk_sp(span_after(codemap::mk_sp(args_start, span.hi), + "(", + self.codemap), + span_for_return(&fd.output).lo); result.push_str(&self.rewrite_args(&fd.inputs, explicit_self, one_line_budget, multi_line_budget, arg_indent, - codemap::mk_sp(span_after(span, "(", self.codemap), - span_for_return(&fd.output).lo))); + args_span)); result.push(')'); // Return type. @@ -222,8 +227,7 @@ impl<'a> FmtVisitor<'a> { multi_line_budget: usize, arg_indent: usize, span: Span) - -> String - { + -> String { let mut arg_item_strs: Vec<_> = args.iter().map(|a| self.rewrite_fn_input(a)).collect(); // Account for sugary self. let mut min_args = 1; @@ -301,15 +305,13 @@ impl<'a> FmtVisitor<'a> { item.item = arg; } - let fmt = ListFormatting { - tactic: ListTactic::HorizontalVertical, - separator: ",", - trailing_separator: SeparatorTactic::Never, - indent: arg_indent, - h_width: one_line_budget, - v_width: multi_line_budget, - ends_with_newline: true, - }; + let fmt = ListFormatting { tactic: ListTactic::HorizontalVertical, + separator: ",", + trailing_separator: SeparatorTactic::Never, + indent: arg_indent, + h_width: one_line_budget, + v_width: multi_line_budget, + ends_with_newline: true, }; write_list(&arg_items, &fmt) } @@ -319,8 +321,7 @@ impl<'a> FmtVisitor<'a> { indent: usize, ret_str_len: usize, newline_brace: bool) - -> (usize, usize, usize) - { + -> (usize, usize, usize) { let mut budgets = None; // Try keeping everything on the same line @@ -377,8 +378,7 @@ impl<'a> FmtVisitor<'a> { vis: ast::Visibility, enum_def: &ast::EnumDef, generics: &ast::Generics, - span: Span) - { + span: Span) { let header_str = self.format_header("enum ", ident, vis); self.changes.push_str_span(span, &header_str); @@ -409,18 +409,14 @@ impl<'a> FmtVisitor<'a> { } // Variant of an enum - fn visit_variant(&mut self, - field: &ast::Variant, - last_field: bool, - next_span_start: BytePos) - { + fn visit_variant(&mut self, field: &ast::Variant, last_field: bool, next_span_start: BytePos) { if self.visit_attrs(&field.node.attrs) { return; } self.format_missing_with_indent(field.span.lo); - match field.node.kind { + 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); @@ -475,23 +471,23 @@ impl<'a> FmtVisitor<'a> { "Enum variant exceeded column limit"); } - self.changes.push_str_span(field.span, &result); - - if !last_field || self.config.enum_trailing_comma { - self.changes.push_str_span(field.span, ","); - } + result }, ast::VariantKind::StructVariantKind(ref struct_def) => { - let result = self.format_struct("", - field.node.name, - field.node.vis, - struct_def, - None, - field.span, - self.block_indent); - - self.changes.push_str_span(field.span, &result) + // TODO Should limit the width, as we have a trailing comma + self.format_struct("", + field.node.name, + field.node.vis, + struct_def, + None, + field.span, + self.block_indent) } + }; + self.changes.push_str_span(field.span, &result); + + if !last_field || self.config.enum_trailing_comma { + self.changes.push_str_span(field.span, ","); } self.last_pos = field.span.hi + BytePos(1); @@ -504,8 +500,8 @@ impl<'a> FmtVisitor<'a> { struct_def: &ast::StructDef, generics: Option<&ast::Generics>, span: Span, - offset: usize) -> String - { + offset: usize) + -> String { let mut result = String::with_capacity(1024); let header_str = self.format_header(item_name, ident, vis); @@ -557,8 +553,7 @@ impl<'a> FmtVisitor<'a> { // Conservative approximation let single_line_cost = (span.hi - struct_def.fields[0].span.lo).0; - let break_line = !is_tuple || - generics_str.contains('\n') || + let break_line = !is_tuple || generics_str.contains('\n') || single_line_cost as usize + used_budget > self.config.max_width; if break_line { @@ -571,15 +566,13 @@ impl<'a> FmtVisitor<'a> { // 1 = , let budget = self.config.ideal_width - offset + self.config.tab_spaces - 1; - let fmt = ListFormatting { - tactic: tactic, - separator: ",", - trailing_separator: self.config.struct_trailing_comma, - indent: offset + self.config.tab_spaces, - h_width: self.config.max_width, - v_width: budget, - ends_with_newline: false, - }; + let fmt = ListFormatting { tactic: tactic, + separator: ",", + trailing_separator: self.config.struct_trailing_comma, + indent: offset + self.config.tab_spaces, + h_width: self.config.max_width, + v_width: budget, + ends_with_newline: false, }; result.push_str(&write_list(&items, &fmt)); @@ -602,8 +595,7 @@ impl<'a> FmtVisitor<'a> { vis: ast::Visibility, struct_def: &ast::StructDef, generics: &ast::Generics, - span: Span) - { + span: Span) { let indent = self.block_indent; let result = self.format_struct("struct ", ident, @@ -616,12 +608,7 @@ impl<'a> FmtVisitor<'a> { self.last_pos = span.hi; } - fn format_header(&self, - item_name: &str, - ident: ast::Ident, - vis: ast::Visibility) - -> String - { + fn format_header(&self, item_name: &str, ident: ast::Ident, vis: ast::Visibility) -> String { format!("{}{}{}", format_visibility(vis), item_name, &token::get_ident(ident)) } @@ -630,8 +617,7 @@ impl<'a> FmtVisitor<'a> { opener: &str, offset: usize, span: Span) - -> String - { + -> String { let mut result = self.rewrite_generics(generics, offset, span); if generics.where_clause.predicates.len() > 0 || result.contains('\n') { @@ -721,15 +707,13 @@ impl<'a> FmtVisitor<'a> { item.item = ty; } - let fmt = ListFormatting { - tactic: ListTactic::HorizontalVertical, - separator: ",", - trailing_separator: SeparatorTactic::Never, - indent: offset + 1, - h_width: budget, - v_width: budget, - ends_with_newline: true, - }; + let fmt = ListFormatting { tactic: ListTactic::HorizontalVertical, + separator: ",", + trailing_separator: SeparatorTactic::Never, + indent: offset + 1, + h_width: budget, + v_width: budget, + ends_with_newline: true, }; result.push_str(&write_list(&items, &fmt)); result.push('>'); @@ -741,8 +725,7 @@ impl<'a> FmtVisitor<'a> { where_clause: &ast::WhereClause, indent: usize, span_end: BytePos) - -> String - { + -> String { let mut result = String::new(); if where_clause.predicates.len() == 0 { return result; @@ -765,15 +748,13 @@ impl<'a> FmtVisitor<'a> { span_end); let budget = self.config.ideal_width + self.config.leeway - indent - 10; - let fmt = ListFormatting { - tactic: ListTactic::Vertical, - separator: ",", - trailing_separator: SeparatorTactic::Never, - indent: indent + 10, - h_width: budget, - v_width: budget, - ends_with_newline: true, - }; + let fmt = ListFormatting { tactic: ListTactic::Vertical, + separator: ",", + trailing_separator: SeparatorTactic::Never, + indent: indent + 10, + h_width: budget, + v_width: budget, + ends_with_newline: true, }; result.push_str(&write_list(&items, &fmt)); result 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/lists.rs b/src/lists.rs index 87a71578e96..155c8ab08cb 100644 --- a/src/lists.rs +++ b/src/lists.rs @@ -48,20 +48,19 @@ pub struct ListFormatting<'a> { pub v_width: usize, // Non-expressions, e.g. items, will have a new line at the end of the list. // Important for comment styles. - pub ends_with_newline: bool + pub ends_with_newline: bool, } pub struct ListItem { pub pre_comment: Option, // Item should include attributes and doc comments pub item: String, - pub post_comment: Option + pub post_comment: Option, } impl ListItem { pub fn is_multiline(&self) -> bool { - self.item.contains('\n') || - self.pre_comment.is_some() || + self.item.contains('\n') || self.pre_comment.is_some() || self.post_comment.as_ref().map(|s| s.contains('\n')).unwrap_or(false) } @@ -70,11 +69,7 @@ impl ListItem { } pub fn from_str>(s: S) -> ListItem { - ListItem { - pre_comment: None, - item: s.into(), - post_comment: None - } + ListItem { pre_comment: None, item: s.into(), post_comment: None } } } @@ -239,8 +234,8 @@ pub fn itemize_list(codemap: &CodeMap, get_item_string: F3, mut prev_span_end: BytePos, next_span_start: BytePos) - -> Vec - where I: Iterator, + -> Vec + where I: Iterator, F1: Fn(&T) -> BytePos, F2: Fn(&T) -> BytePos, F3: Fn(&T) -> String diff --git a/src/missed_spans.rs b/src/missed_spans.rs index c861d631be8..d560b3f2027 100644 --- a/src/missed_spans.rs +++ b/src/missed_spans.rs @@ -36,8 +36,7 @@ impl<'a> FmtVisitor<'a> { fn format_missing_inner(&mut self, end: BytePos, - process_last_snippet: F) - { + process_last_snippet: F) { let start = self.last_pos; debug!("format_missing_inner: {:?} to {:?}", self.codemap.lookup_char_pos(start), diff --git a/src/types.rs b/src/types.rs index c16b9eadf4e..6880cd8bcc2 100644 --- a/src/types.rs +++ b/src/types.rs @@ -15,8 +15,7 @@ use syntax::parse::token; use syntax::print::pprust; impl<'a> FmtVisitor<'a> { - pub fn rewrite_pred(&self, predicate: &ast::WherePredicate) -> String - { + pub fn rewrite_pred(&self, predicate: &ast::WherePredicate) -> String { // TODO dead spans // TODO assumes we'll always fit on one line... match predicate { @@ -49,8 +48,7 @@ impl<'a> FmtVisitor<'a> { } } - pub fn rewrite_lifetime_def(&self, lifetime: &ast::LifetimeDef) -> String - { + pub fn rewrite_lifetime_def(&self, lifetime: &ast::LifetimeDef) -> String { if lifetime.bounds.len() == 0 { return pprust::lifetime_to_string(&lifetime.lifetime); } @@ -60,8 +58,7 @@ impl<'a> FmtVisitor<'a> { lifetime.bounds.iter().map(|l| pprust::lifetime_to_string(l)).collect::>().connect(" + ")) } - pub fn rewrite_ty_bound(&self, bound: &ast::TyParamBound) -> String - { + pub fn rewrite_ty_bound(&self, bound: &ast::TyParamBound) -> String { match *bound { ast::TyParamBound::TraitTyParamBound(ref tref, ast::TraitBoundModifier::None) => { self.rewrite_poly_trait_ref(tref) @@ -75,8 +72,7 @@ impl<'a> FmtVisitor<'a> { } } - pub fn rewrite_ty_param(&self, ty_param: &ast::TyParam) -> String - { + pub fn rewrite_ty_param(&self, ty_param: &ast::TyParam) -> String { let mut result = String::with_capacity(128); result.push_str(&token::get_ident(ty_param.ident)); if ty_param.bounds.len() > 0 { @@ -91,8 +87,7 @@ impl<'a> FmtVisitor<'a> { result } - fn rewrite_poly_trait_ref(&self, t: &ast::PolyTraitRef) -> String - { + fn rewrite_poly_trait_ref(&self, t: &ast::PolyTraitRef) -> String { if t.bound_lifetimes.len() > 0 { format!("for<{}> {}", t.bound_lifetimes.iter().map(|l| self.rewrite_lifetime_def(l)).collect::>().connect(", "), diff --git a/src/utils.rs b/src/utils.rs index de17f989f7a..47203a0754f 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use syntax::ast::{Visibility, Attribute, MetaItem, MetaItem_}; +use syntax::ast::{self, Visibility, Attribute, MetaItem, MetaItem_}; use syntax::codemap::{CodeMap, Span, BytePos}; use comment::FindUncommented; @@ -72,6 +72,14 @@ pub fn contains_skip(attrs: &[Attribute]) -> bool { attrs.iter().any(|a| is_skip(&a.node.value)) } +// Find the end of a TyParam +pub fn end_typaram(typaram: &ast::TyParam) -> BytePos { + typaram.bounds.last().map(|bound| match *bound { + ast::RegionTyParamBound(ref lt) => lt.span, + ast::TraitTyParamBound(ref prt, _) => prt.span, + }).unwrap_or(typaram.span).hi +} + #[inline] #[cfg(target_pointer_width="64")] // Based on the trick layed out at diff --git a/src/visitor.rs b/src/visitor.rs index df50f6cda27..5c15e1bf523 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,24 +274,19 @@ 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); } } 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), - last_pos: BytePos(0), - block_indent: 0, - config: config - } + FmtVisitor { codemap: codemap, + changes: ChangeSet::from_codemap(codemap), + last_pos: BytePos(0), + block_indent: 0, + config: config, } } pub fn snippet(&self, span: Span) -> String { @@ -352,4 +354,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/enum.rs b/tests/target/enum.rs index 8c534ef89c8..2e2e47e25c2 100644 --- a/tests/target/enum.rs +++ b/tests/target/enum.rs @@ -40,5 +40,8 @@ enum StructLikeVariants { // Pre-comment #[Attr50] y: SomeType, // Aanother Comment - } + }, + SL { + a: A, + }, } diff --git a/tests/target/fn.rs b/tests/target/fn.rs index dff8085136e..bc05efa5351 100644 --- a/tests/target/fn.rs +++ b/tests/target/fn.rs @@ -34,6 +34,9 @@ fn foo(a: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA, } +fn foo B /* paren inside generics */>() { +} + impl Foo { fn with_no_errors(&mut self, f: F) -> T where F: FnOnce(&mut Resolver) -> T 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;