Merge pull request #208 from cassiersg/rewrite-attrs

Implement Rewrite for [ast::Attribute]
This commit is contained in:
cassiersg 2015-08-27 22:38:31 +02:00
commit 9e4e445315
6 changed files with 128 additions and 61 deletions

View File

@ -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<String> {
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<String> {
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<String> {
// 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<String> {
let operator_str = match op {
Some(op) => context.codemap.span_to_snippet(op.span).unwrap(),
Some(op) => context.snippet(op.span),
None => "=".to_owned(),
};

View File

@ -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));

View File

@ -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()
}
}

View File

@ -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<String> {
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)
}
}

43
tests/source/attrib.rs Normal file
View File

@ -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 {
}
}

View File

@ -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 {
}
}