diff --git a/src/expr.rs b/src/expr.rs index 14659815d72..f39dece3272 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -31,7 +31,7 @@ fn rewrite(&self, context: &RewriteContext, width: usize, offset: usize) -> Opti ast::Lit_::LitStr(ref is, ast::StrStyle::CookedStr) => { rewrite_string_lit(context, &is, l.span, width, offset) } - _ => context.codemap.span_to_snippet(self.span).ok(), + _ => Some(context.snippet(self.span)), } } ast::Expr_::ExprCall(ref callee, ref args) => { @@ -137,7 +137,7 @@ fn rewrite(&self, context: &RewriteContext, width: usize, offset: usize) -> Opti _ => { // We do not format these expressions yet, but they should still // satisfy our width restrictions. - let snippet = context.codemap.span_to_snippet(self.span).unwrap(); + let snippet = context.snippet(self.span); { let mut lines = snippet.lines(); @@ -243,7 +243,7 @@ fn rewrite_closure(capture: ast::CaptureClause, impl Rewrite for ast::Block { fn rewrite(&self, context: &RewriteContext, width: usize, offset: usize) -> Option { - let user_str = context.codemap.span_to_snippet(self.span).unwrap(); + let user_str = context.snippet(self.span); if user_str == "{}" && width >= 2 { return Some(user_str); } @@ -254,7 +254,7 @@ fn rewrite(&self, context: &RewriteContext, width: usize, offset: usize) -> Opti let prefix = match self.rules { ast::BlockCheckMode::PushUnsafeBlock(..) | ast::BlockCheckMode::UnsafeBlock(..) => { - let snippet = try_opt!(context.codemap.span_to_snippet(self.span).ok()); + let snippet = context.snippet(self.span); let open_pos = try_opt!(snippet.find_uncommented("{")); visitor.last_pos = self.span.lo + BytePos(open_pos as u32); @@ -289,7 +289,7 @@ fn rewrite(&self, context: &RewriteContext, width: usize, offset: usize) -> Opti // FIXME(#18): implement pattern formatting impl Rewrite for ast::Pat { fn rewrite(&self, context: &RewriteContext, _: usize, _: usize) -> Option { - context.codemap.span_to_snippet(self.span).ok() + Some(context.snippet(self.span)) } } @@ -547,11 +547,9 @@ fn rewrite_match(context: &RewriteContext, for (i, arm) in arms.iter().enumerate() { // Make sure we get the stuff between arms. let missed_str = if i == 0 { - context.codemap.span_to_snippet(mk_sp(open_brace_pos + BytePos(1), - arm_start_pos(arm))).unwrap() + context.snippet(mk_sp(open_brace_pos + BytePos(1), arm_start_pos(arm))) } else { - context.codemap.span_to_snippet(mk_sp(arm_end_pos(&arms[i-1]), - arm_start_pos(arm))).unwrap() + context.snippet(mk_sp(arm_end_pos(&arms[i-1]), arm_start_pos(arm))) }; let missed_str = match missed_str.find_uncommented(",") { Some(n) => &missed_str[n+1..], @@ -582,8 +580,7 @@ fn rewrite_match(context: &RewriteContext, result.push_str(arm_str); } else { // We couldn't format the arm, just reproduce the source. - let snippet = context.codemap.span_to_snippet(mk_sp(arm_start_pos(arm), - arm_end_pos(arm))).unwrap(); + let snippet = context.snippet(mk_sp(arm_start_pos(arm), arm_end_pos(arm))); result.push_str(&snippet); } } @@ -626,8 +623,7 @@ fn rewrite(&self, context: &RewriteContext, width: usize, offset: usize) -> Opti attr_visitor.last_pos = attrs[0].span.lo; if attr_visitor.visit_attrs(attrs) { // Attributes included a skip instruction. - let snippet = context.codemap.span_to_snippet(mk_sp(attrs[0].span.lo, - body.span.hi)).unwrap(); + let snippet = context.snippet(mk_sp(attrs[0].span.lo, body.span.hi)); return Some(snippet); } attr_visitor.format_missing(pats[0].span.lo); @@ -652,7 +648,7 @@ fn rewrite(&self, context: &RewriteContext, width: usize, offset: usize) -> Opti // If the patterns were previously stacked, keep them stacked. // FIXME should be an option. let pat_span = mk_sp(pats[0].span.lo, pats[pats.len() - 1].span.hi); - let pat_str = context.codemap.span_to_snippet(pat_span).unwrap(); + let pat_str = context.snippet(pat_span); vertical = pat_str.find('\n').is_some(); } @@ -831,7 +827,7 @@ fn rewrite_string_lit(context: &RewriteContext, let l_loc = context.codemap.lookup_char_pos(span.lo); let r_loc = context.codemap.lookup_char_pos(span.hi); if l_loc.line == r_loc.line && r_loc.col.to_usize() <= context.config.max_width { - return context.codemap.span_to_snippet(span).ok(); + return Some(context.snippet(span)); } let fmt = StringFormat { opener: "\"", @@ -880,7 +876,7 @@ fn rewrite_call(context: &RewriteContext, // Take old span when rewrite fails. |item| { item.rewrite(inner_context, remaining_width, offset) - .unwrap_or(context.codemap.span_to_snippet(item.span).unwrap()) + .unwrap_or(context.snippet(item.span)) }, callee.span.hi + BytePos(1), span.hi); @@ -977,15 +973,13 @@ enum StructLitField<'a> { match *item { StructLitField::Regular(ref field) => { rewrite_field(inner_context, &field, h_budget, indent) - .unwrap_or(context.codemap.span_to_snippet(field.span) - .unwrap()) + .unwrap_or(context.snippet(field.span)) } StructLitField::Base(ref expr) => { // 2 = .. expr.rewrite(inner_context, h_budget - 2, indent + 2) .map(|s| format!("..{}", s)) - .unwrap_or(context.codemap.span_to_snippet(expr.span) - .unwrap()) + .unwrap_or(context.snippet(expr.span)) } } }, @@ -1053,7 +1047,7 @@ fn rewrite_tuple_lit(context: &RewriteContext, |item| { let inner_width = context.config.max_width - indent - 1; item.rewrite(context, inner_width, indent) - .unwrap_or(context.codemap.span_to_snippet(item.span).unwrap()) + .unwrap_or(context.snippet(item.span)) }, span.lo + BytePos(1), // Remove parens span.hi - BytePos(1)); @@ -1072,7 +1066,7 @@ fn rewrite_binary_op(context: &RewriteContext, -> Option { // FIXME: format comments between operands and operator - let operator_str = context.codemap.span_to_snippet(op.span).unwrap(); + let operator_str = context.snippet(op.span); // Get "full width" rhs and see if it fits on the current line. This // usually works fairly well since it tends to place operands of @@ -1150,7 +1144,7 @@ fn rewrite_assignment(context: &RewriteContext, offset: usize) -> Option { let operator_str = match op { - Some(op) => context.codemap.span_to_snippet(op.span).unwrap(), + Some(op) => context.snippet(op.span), None => "=".to_owned(), }; diff --git a/src/items.rs b/src/items.rs index 1501a904fdf..bcc851a5b35 100644 --- a/src/items.rs +++ b/src/items.rs @@ -17,7 +17,6 @@ use expr::rewrite_assign_rhs; use comment::FindUncommented; use visitor::FmtVisitor; - use rewrite::Rewrite; use config::Config; @@ -699,7 +698,11 @@ fn format_field(&self, field: &ast::StructField) -> String { let typ = pprust::ty_to_string(&field.node.ty); let indent = self.block_indent + self.config.tab_spaces; - let mut attr_str = self.rewrite_attrs(&field.node.attrs, indent); + let mut attr_str = field.node.attrs + .rewrite(&self.get_context(), + self.config.max_width - indent, + indent) + .unwrap(); if !attr_str.is_empty() { attr_str.push('\n'); attr_str.push_str(&make_indent(indent)); diff --git a/src/rewrite.rs b/src/rewrite.rs index d30d81a4885..5f1549846b5 100644 --- a/src/rewrite.rs +++ b/src/rewrite.rs @@ -10,7 +10,7 @@ // A generic trait to abstract the rewriting of an element (of the AST). -use syntax::codemap::CodeMap; +use syntax::codemap::{CodeMap, Span}; use config::Config; @@ -39,4 +39,8 @@ pub fn nested_context(&self) -> RewriteContext<'a> { block_indent: self.block_indent + self.config.tab_spaces, } } + + pub fn snippet(&self, span: Span) -> String { + self.codemap.span_to_snippet(span).unwrap() + } } diff --git a/src/visitor.rs b/src/visitor.rs index 20909391f09..b773a20fe6f 100644 --- a/src/visitor.rs +++ b/src/visitor.rs @@ -17,6 +17,7 @@ use utils; use config::Config; use rewrite::{Rewrite, RewriteContext}; +use comment::rewrite_comment; pub struct FmtVisitor<'a> { pub codemap: &'a CodeMap, @@ -293,7 +294,10 @@ pub fn visit_attrs(&mut self, attrs: &[ast::Attribute]) -> bool { if utils::contains_skip(attrs) { true } else { - let rewrite = self.rewrite_attrs(attrs, self.block_indent); + let rewrite = attrs.rewrite(&self.get_context(), + self.config.max_width - self.block_indent, + self.block_indent) + .unwrap(); self.buffer.push_str(&rewrite); let last = attrs.last().unwrap(); self.last_pos = last.span.hi; @@ -301,40 +305,6 @@ pub fn visit_attrs(&mut self, attrs: &[ast::Attribute]) -> bool { } } - pub fn rewrite_attrs(&self, attrs: &[ast::Attribute], indent: usize) -> String { - let mut result = String::new(); - let indent = utils::make_indent(indent); - - for (i, a) in attrs.iter().enumerate() { - let a_str = self.snippet(a.span); - - if i > 0 { - let comment = self.snippet(codemap::mk_sp(attrs[i-1].span.hi, a.span.lo)); - // This particular horror show is to preserve line breaks in between doc - // comments. An alternative would be to force such line breaks to start - // with the usual doc comment token. - let multi_line = a_str.starts_with("//") && comment.matches('\n').count() > 1; - let comment = comment.trim(); - if !comment.is_empty() { - result.push_str(&indent); - result.push_str(comment); - result.push('\n'); - } else if multi_line { - result.push('\n'); - } - result.push_str(&indent); - } - - result.push_str(&a_str); - - if i < attrs.len() - 1 { - result.push('\n'); - } - } - - result - } - fn format_mod(&mut self, m: &ast::Mod, s: Span, ident: ast::Ident) { debug!("FmtVisitor::format_mod: ident: {:?}, span: {:?}", ident, s); @@ -402,3 +372,46 @@ pub fn get_context(&self) -> RewriteContext { } } } + +impl<'a> Rewrite for [ast::Attribute] { + fn rewrite(&self, context: &RewriteContext, _: usize, offset: usize) -> Option { + let mut result = String::new(); + if self.is_empty() { + return Some(result); + } + let indent = utils::make_indent(offset); + + for (i, a) in self.iter().enumerate() { + let a_str = context.snippet(a.span); + + if i > 0 { + let comment = context.snippet(codemap::mk_sp(self[i-1].span.hi, a.span.lo)); + // This particular horror show is to preserve line breaks in between doc + // comments. An alternative would be to force such line breaks to start + // with the usual doc comment token. + let multi_line = a_str.starts_with("//") && comment.matches('\n').count() > 1; + let comment = comment.trim(); + if !comment.is_empty() { + let comment = rewrite_comment(comment, + false, + context.config.max_width - offset, + offset); + result.push_str(&indent); + result.push_str(&comment); + result.push('\n'); + } else if multi_line { + result.push('\n'); + } + result.push_str(&indent); + } + + result.push_str(&a_str); + + if i < self.len() - 1 { + result.push('\n'); + } + } + + Some(result) + } +} diff --git a/tests/source/attrib.rs b/tests/source/attrib.rs new file mode 100644 index 00000000000..ac44a6504fd --- /dev/null +++ b/tests/source/attrib.rs @@ -0,0 +1,43 @@ +// Test attributes and doc comments are preserved. + +/// Blah blah blah. +/// Blah blah blah. +/// Blah blah blah. +/// Blah blah blah. + +/// Blah blah blah. +impl Bar { + /// Blah blah blooo. + /// Blah blah blooo. + /// Blah blah blooo. + /// Blah blah blooo. + #[an_attribute] + fn foo(&mut self) -> isize { + } + + /// Blah blah bing. + /// Blah blah bing. + /// Blah blah bing. + + + /// Blah blah bing. + /// Blah blah bing. + /// Blah blah bing. + pub fn f2(self) { + (foo, bar) + } + + #[another_attribute] + fn f3(self) -> Dog { + } + + /// Blah blah bing. + + #[attrib1] + /// Blah blah bing. + #[attrib2] + // Another comment that needs rewrite because it's tooooooooooooooooooooooooooooooo loooooooooooong. + /// Blah blah bing. + fn f4(self) -> Cat { + } +} diff --git a/tests/target/attrib.rs b/tests/target/attrib.rs index ee7da10081e..62657ad3b5d 100644 --- a/tests/target/attrib.rs +++ b/tests/target/attrib.rs @@ -29,4 +29,14 @@ pub fn f2(self) { #[another_attribute] fn f3(self) -> Dog { } + + /// Blah blah bing. + #[attrib1] + /// Blah blah bing. + #[attrib2] + // Another comment that needs rewrite because it's tooooooooooooooooooooooooooooooo + // loooooooooooong. + /// Blah blah bing. + fn f4(self) -> Cat { + } }