Implement basic chain formatting

This commit is contained in:
Marcus Klaas 2015-09-11 00:52:16 +02:00
parent 1af301c33d
commit c680bb4030
12 changed files with 352 additions and 184 deletions

133
src/chains.rs Normal file
View File

@ -0,0 +1,133 @@
// 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use rewrite::{Rewrite, RewriteContext};
use utils::{span_after, make_indent, extra_offset};
use expr::rewrite_call;
use syntax::{ast, ptr};
use syntax::codemap::{mk_sp, Span};
use syntax::print::pprust;
pub fn rewrite_chain(orig_expr: &ast::Expr,
context: &RewriteContext,
width: usize,
offset: usize)
-> Option<String> {
let mut expr = orig_expr;
let mut rewrites = Vec::new();
let indent = context.block_indent + context.config.tab_spaces;
let max_width = context.config.max_width - context.config.tab_spaces;
loop {
match expr.node {
ast::Expr_::ExprMethodCall(ref method_name, ref types, ref expressions) => {
// FIXME: a lot of duplication between this and the
// rewrite_method_call in expr.rs.
let new_span = mk_sp(expressions[0].span.hi, expr.span.hi);
let lo = span_after(new_span, "(", context.codemap);
let new_span = mk_sp(lo, expr.span.hi);
let rewrite = rewrite_method_call(method_name.node,
types,
&expressions[1..],
new_span,
context,
max_width,
indent);
rewrites.push(try_opt!(rewrite));
expr = &expressions[0];
}
ast::Expr_::ExprField(ref subexpr, ref field) => {
expr = subexpr;
rewrites.push(format!(".{}", field.node));
}
ast::Expr_::ExprTupField(ref subexpr, ref field) => {
expr = subexpr;
rewrites.push(format!(".{}", field.node));
}
_ => break,
}
}
let parent_rewrite = try_opt!(expr.rewrite(context, width, offset));
// TODO: add exception for when rewrites.len() == 1
if rewrites.len() == 1 {
let extra_offset = extra_offset(&parent_rewrite, offset);
let max_width = try_opt!(width.checked_sub(extra_offset));
// FIXME: massive duplication
let rerewrite = match orig_expr.node {
ast::Expr_::ExprMethodCall(ref method_name, ref types, ref expressions) => {
let new_span = mk_sp(expressions[0].span.hi, orig_expr.span.hi);
let lo = span_after(new_span, "(", context.codemap);
let new_span = mk_sp(lo, orig_expr.span.hi);
rewrite_method_call(method_name.node,
types,
&expressions[1..],
new_span,
context,
max_width,
offset + extra_offset)
}
ast::Expr_::ExprField(_, ref field) => {
Some(format!(".{}", field.node))
}
ast::Expr_::ExprTupField(_, ref field) => {
Some(format!(".{}", field.node))
}
_ => unreachable!(),
};
return Some(format!("{}{}", parent_rewrite, try_opt!(rerewrite)));
}
let total_width = rewrites.iter().fold(0, |a, b| a + b.len()) + parent_rewrite.len();
let connector = if total_width <= width && rewrites.iter().all(|s| !s.contains('\n')) {
String::new()
} else {
format!("\n{}", make_indent(indent))
};
// FIXME: don't do this. There's a more efficient way. VecDeque?
rewrites.reverse();
// Put the first link on the same line as parent, if it fits.
let first_connector = if parent_rewrite.len() + rewrites[0].len() <= width &&
!rewrites[0].contains('\n') {
""
} else {
&connector[..]
};
Some(format!("{}{}{}", parent_rewrite, first_connector, rewrites.join(&connector)))
}
fn rewrite_method_call(method_name: ast::Ident,
types: &[ptr::P<ast::Ty>],
args: &[ptr::P<ast::Expr>],
span: Span,
context: &RewriteContext,
width: usize,
offset: usize)
-> Option<String> {
let type_str = if types.is_empty() {
String::new()
} else {
let type_list = types.iter().map(|ty| pprust::ty_to_string(ty)).collect::<Vec<_>>();
format!("::<{}>", type_list.join(", "))
};
let callee_str = format!(".{}{}", method_name, type_str);
rewrite_call(context, &callee_str, args, span, width, offset)
}

View File

@ -25,8 +25,7 @@ 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 max_chars = width.checked_sub(closer.len() + opener.len()).unwrap_or(1);
let fmt = StringFormat {
opener: "",
@ -41,17 +40,18 @@ pub fn rewrite_comment(orig: &str, block_style: bool, width: usize, offset: usiz
let indent_str = make_indent(offset);
let line_breaks = s.chars().filter(|&c| c == '\n').count();
let (_, mut s) = s.lines().enumerate()
let (_, mut s) = s.lines()
.enumerate()
.map(|(i, mut line)| {
line = line.trim();
line = line.trim();
// Drop old closer.
if i == line_breaks && line.ends_with("*/") && !line.starts_with("//") {
line = &line[..(line.len() - 2)];
}
if i == line_breaks && line.ends_with("*/") && !line.starts_with("//") {
line = &line[..(line.len() - 2)];
}
line.trim_right()
})
line.trim_right()
})
.map(left_trim_comment_line)
.map(|line| {
if line_breaks == 0 {
@ -160,9 +160,34 @@ fn comment_end() {
/// Returns true if text contains any comment.
pub fn contains_comment(text: &str) -> bool {
CharClasses::new(text.chars()).any(|(kind, _)| kind == CodeCharKind::Comment )
CharClasses::new(text.chars()).any(|(kind, _)| kind == CodeCharKind::Comment)
}
pub fn uncommented(text: &str) -> String {
CharClasses::new(text.chars())
.filter_map(|(s, c)| {
match s {
CodeCharKind::Normal => Some(c),
CodeCharKind::Comment => None,
}
})
.collect()
}
#[test]
fn test_uncommented() {
assert_eq!(&uncommented("abc/*...*/"), "abc");
assert_eq!(&uncommented("// .... /* \n../* /* *** / */ */a/* // */c\n"), "..ac\n");
assert_eq!(&uncommented("abc \" /* */\" qsdf"), "abc \" /* */\" qsdf");
}
#[test]
fn test_contains_comment() {
assert_eq!(contains_comment("abc"), false);
assert_eq!(contains_comment("abc // qsdf"), true);
assert_eq!(contains_comment("abc /* kqsdf"), true);
assert_eq!(contains_comment("abc \" /* */\" qsdf"), false);
}
struct CharClasses<T>
where T: Iterator,

View File

@ -9,6 +9,7 @@
// except according to those terms.
use std::cmp::Ordering;
use std::borrow::Borrow;
use rewrite::{Rewrite, RewriteContext};
use lists::{write_list, itemize_list, ListFormatting, SeparatorTactic, ListTactic};
@ -21,6 +22,7 @@ use config::{BlockIndentStyle, MultilineStyle};
use comment::{FindUncommented, rewrite_comment, contains_comment};
use types::rewrite_path;
use items::{span_lo_for_arg, span_hi_for_arg, rewrite_fn_input};
use chains::rewrite_chain;
use syntax::{ast, ptr};
use syntax::codemap::{CodeMap, Span, BytePos, mk_sp};
@ -38,7 +40,16 @@ impl Rewrite for ast::Expr {
}
}
ast::Expr_::ExprCall(ref callee, ref args) => {
rewrite_call(context, callee, args, self.span, width, offset)
// // FIXME using byte lens instead of char lens (and probably all over the place too)
// // 2 is for parens
// let max_callee_width = try_opt!(width.checked_sub(2));
// let callee_str = try_opt!(callee.rewrite(context, max_callee_width, offset));
// let new_span = mk_sp(callee.span.hi, self.span.hi);
// let lo = span_after(new_span, "(", context.codemap);
// let new_span = mk_sp(lo, self.span.hi);
rewrite_call(context, &**callee, args, self.span, width, offset)
}
ast::Expr_::ExprParen(ref subexpr) => {
rewrite_paren(context, subexpr, width, offset)
@ -137,6 +148,11 @@ impl Rewrite for ast::Expr {
ast::Expr_::ExprClosure(capture, ref fn_decl, ref body) => {
rewrite_closure(capture, fn_decl, body, self.span, context, width, offset)
}
ast::Expr_::ExprField(..) |
ast::Expr_::ExprTupField(..) |
ast::Expr_::ExprMethodCall(..) => {
rewrite_chain(self, context, width, offset)
}
// We do not format these expressions yet, but they should still
// satisfy our width restrictions.
_ => wrap_str(context.snippet(self.span), context.config.max_width, width, offset),
@ -393,9 +409,9 @@ impl<'a> Rewrite for Loop<'a> {
};
// FIXME: this drops any comment between "loop" and the block.
self.block.rewrite(context, width, offset).map(|result| {
format!("{}{}{} {}", label_string, self.keyword, pat_expr_string, result)
})
self.block
.rewrite(context, width, offset)
.map(|result| format!("{}{}{} {}", label_string, self.keyword, pat_expr_string, result))
}
}
@ -762,9 +778,7 @@ fn rewrite_guard(context: &RewriteContext,
// 4 = ` if `, 5 = ` => {`
let overhead = pattern_width + 4 + 5;
if overhead < width {
let cond_str = guard.rewrite(context,
width - overhead,
offset + pattern_width + 4);
let cond_str = guard.rewrite(context, width - overhead, offset + pattern_width + 4);
if let Some(cond_str) = cond_str {
return Some(format!(" if {}", cond_str));
}
@ -866,36 +880,39 @@ fn rewrite_string_lit(context: &RewriteContext,
Some(rewrite_string(str_lit, &fmt))
}
fn rewrite_call(context: &RewriteContext,
callee: &ast::Expr,
args: &[ptr::P<ast::Expr>],
span: Span,
width: usize,
offset: usize)
-> Option<String> {
let callback = |callee_max_width| {
rewrite_call_inner(context,
callee,
callee_max_width,
args,
span,
width,
offset)
};
pub fn rewrite_call<R>(context: &RewriteContext,
callee: &R,
args: &[ptr::P<ast::Expr>],
span: Span,
width: usize,
offset: usize)
-> Option<String>
where R: Rewrite
{
// 2 is for parens
let max_width = try_opt!(width.checked_sub(2));
binary_search(1, max_width, callback)
binary_search(1, max_width, |callee_max_width| {
rewrite_call_inner(context,
callee,
callee_max_width,
args,
span,
width,
offset)
})
}
fn rewrite_call_inner(context: &RewriteContext,
callee: &ast::Expr,
max_callee_width: usize,
args: &[ptr::P<ast::Expr>],
span: Span,
width: usize,
offset: usize)
-> Result<String, Ordering> {
fn rewrite_call_inner<R>(context: &RewriteContext,
callee: &R,
max_callee_width: usize,
args: &[ptr::P<ast::Expr>],
span: Span,
width: usize,
offset: usize)
-> Result<String, Ordering>
where R: Rewrite
{
let callee = callee.borrow();
// FIXME using byte lens instead of char lens (and probably all over the
// place too)
let callee_str = match callee.rewrite(context, max_callee_width, offset) {
@ -929,7 +946,7 @@ fn rewrite_call_inner(context: &RewriteContext,
item.rewrite(&inner_context, remaining_width, offset)
.unwrap_or(context.snippet(item.span))
},
callee.span.hi + BytePos(1),
span.lo,
span.hi);
let fmt = ListFormatting::for_fn(remaining_width, offset);
@ -1004,8 +1021,9 @@ fn rewrite_struct_lit<'a>(context: &RewriteContext,
}
};
let field_iter = fields.into_iter().map(StructLitField::Regular)
.chain(base.into_iter().map(StructLitField::Base));
let field_iter = fields.into_iter()
.map(StructLitField::Regular)
.chain(base.into_iter().map(StructLitField::Base));
let inner_context = &RewriteContext { block_indent: indent, ..*context };
@ -1016,10 +1034,10 @@ fn rewrite_struct_lit<'a>(context: &RewriteContext,
match *item {
StructLitField::Regular(ref field) => field.span.lo,
StructLitField::Base(ref expr) => {
let last_field_hi =
fields.last().map_or(span.lo, |field| field.span.hi);
let snippet =
context.snippet(mk_sp(last_field_hi, expr.span.lo));
let last_field_hi = fields.last()
.map_or(span.lo, |field| field.span.hi);
let snippet = context.snippet(mk_sp(last_field_hi,
expr.span.lo));
let pos = snippet.find_uncommented("..").unwrap();
last_field_hi + BytePos(pos as u32)
}
@ -1035,7 +1053,7 @@ fn rewrite_struct_lit<'a>(context: &RewriteContext,
match *item {
StructLitField::Regular(ref field) => {
rewrite_field(inner_context, &field, h_budget, indent)
.unwrap_or(context.snippet(field.span))
.unwrap_or(context.snippet(field.span))
}
StructLitField::Base(ref expr) => {
// 2 = ..
@ -1152,10 +1170,7 @@ fn rewrite_binary_op(context: &RewriteContext,
// worth trying to put everything on one line.
if rhs_result.len() + 2 + operator_str.len() < width && !rhs_result.contains('\n') {
// 1 = space between lhs expr and operator
if let Some(mut result) = lhs.rewrite(context,
width - 1 - operator_str.len(),
offset) {
if let Some(mut result) = lhs.rewrite(context, width - 1 - operator_str.len(), offset) {
result.push(' ');
result.push_str(&operator_str);
result.push(' ');
@ -1167,9 +1182,7 @@ fn rewrite_binary_op(context: &RewriteContext,
return Some(result);
}
if let Some(rhs_result) = rhs.rewrite(context,
remaining_width,
offset + result.len()) {
if let Some(rhs_result) = rhs.rewrite(context, remaining_width, offset + result.len()) {
if rhs_result.len() <= remaining_width {
result.push_str(&rhs_result);
return Some(result);

View File

@ -211,8 +211,10 @@ impl<'a> FmtVisitor<'a> {
let ret_str = fd.output.rewrite(&context, self.config.max_width - indent, indent).unwrap();
// Args.
let (one_line_budget, multi_line_budget, mut arg_indent) =
self.compute_budgets_for_args(&result, indent, ret_str.len(), newline_brace);
let (one_line_budget, multi_line_budget, mut arg_indent) = self.compute_budgets_for_args(&result,
indent,
ret_str.len(),
newline_brace);
debug!("rewrite_fn: one_line_budget: {}, multi_line_budget: {}, arg_indent: {}",
one_line_budget, multi_line_budget, arg_indent);
@ -237,10 +239,7 @@ impl<'a> FmtVisitor<'a> {
}
// 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_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),
@ -333,12 +332,13 @@ impl<'a> FmtVisitor<'a> {
// Account for sugary self.
// FIXME: the comment for the self argument is dropped. This is blocked
// on rust issue #27522.
let min_args = explicit_self.and_then(|explicit_self| {
rewrite_explicit_self(explicit_self, args)
}).map(|self_str| {
arg_item_strs[0] = self_str;
2
}).unwrap_or(1);
let min_args = explicit_self
.and_then(|explicit_self| rewrite_explicit_self(explicit_self, args))
.map(|self_str| {
arg_item_strs[0] = self_str;
2
})
.unwrap_or(1);
// Comments between args
let mut arg_items = Vec::new();
@ -760,11 +760,10 @@ impl<'a> FmtVisitor<'a> {
let typ = field.node.ty.rewrite(&self.get_context(), 1000, 0).unwrap();
let indent = self.block_indent + self.config.tab_spaces;
let mut attr_str = field.node.attrs
.rewrite(&self.get_context(),
self.config.max_width - indent,
indent)
.unwrap();
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));
@ -803,22 +802,20 @@ impl<'a> FmtVisitor<'a> {
// Strings for the generics.
let context = self.get_context();
// FIXME: don't unwrap
let lt_strs = lifetimes.iter().map(|lt| {
lt.rewrite(&context, h_budget, offset).unwrap()
});
let ty_strs = tys.iter().map(|ty_param| {
ty_param.rewrite(&context, h_budget, offset).unwrap()
});
let lt_strs = lifetimes.iter().map(|lt| lt.rewrite(&context, h_budget, offset).unwrap());
let ty_strs = tys.iter()
.map(|ty_param| ty_param.rewrite(&context, h_budget, offset).unwrap());
// Extract comments between generics.
let lt_spans = lifetimes.iter().map(|l| {
let hi = if l.bounds.is_empty() {
l.lifetime.span.hi
} else {
l.bounds[l.bounds.len() - 1].span.hi
};
codemap::mk_sp(l.lifetime.span.lo, hi)
});
let lt_spans = lifetimes.iter()
.map(|l| {
let hi = if l.bounds.is_empty() {
l.lifetime.span.hi
} else {
l.bounds[l.bounds.len() - 1].span.hi
};
codemap::mk_sp(l.lifetime.span.lo, hi)
});
let ty_spans = tys.iter().map(span_for_ty_param);
let items = itemize_list(self.codemap,

View File

@ -70,6 +70,7 @@ mod string;
mod comment;
mod modules;
pub mod rustfmt_diff;
mod chains;
const MIN_STRING: usize = 10;
// When we get scoped annotations, we should have rustfmt::skip.

View File

@ -283,22 +283,22 @@ impl<'a, T, I, F1, F2, F3> Iterator for ListItems<'a, I, F1, F2, F3>
};
// Post-comment
let next_start = match self.inner.peek() {
Some(ref next_item) => (self.get_lo)(next_item),
None => self.next_span_start
};
let post_snippet = self.codemap.span_to_snippet(codemap::mk_sp((self.get_hi)(&item),
next_start))
.unwrap();
let next_start = match self.inner.peek() {
Some(ref next_item) => (self.get_lo)(next_item),
None => self.next_span_start,
};
let post_snippet = self.codemap
.span_to_snippet(codemap::mk_sp((self.get_hi)(&item), next_start))
.unwrap();
let comment_end = match self.inner.peek() {
Some(..) => {
let block_open_index = post_snippet.find("/*");
let newline_index = post_snippet.find('\n');
let separator_index = post_snippet.find_uncommented(",").unwrap();
let comment_end = match self.inner.peek() {
Some(..) => {
let block_open_index = post_snippet.find("/*");
let newline_index = post_snippet.find('\n');
let separator_index = post_snippet.find_uncommented(",").unwrap();
match (block_open_index, newline_index) {
// Separator before comment, with the next item on same line.
match (block_open_index, newline_index) {
// Separator before comment, with the next item on same line.
// Comment belongs to next item.
(Some(i), None) if i > separator_index => {
separator_index + 1

View File

@ -17,21 +17,20 @@ impl<'a> FmtVisitor<'a> {
// TODO these format_missing methods are ugly. Refactor and add unit tests
// for the central whitespace stripping loop.
pub fn format_missing(&mut self, end: BytePos) {
self.format_missing_inner(end, |this, last_snippet, _| {
this.buffer.push_str(last_snippet)
})
self.format_missing_inner(end, |this, last_snippet, _| this.buffer.push_str(last_snippet))
}
pub fn format_missing_with_indent(&mut self, end: BytePos) {
self.format_missing_inner(end, |this, last_snippet, snippet| {
this.buffer.push_str(last_snippet.trim_right());
if last_snippet == snippet {
self.format_missing_inner(end,
|this, last_snippet, snippet| {
this.buffer.push_str(last_snippet.trim_right());
if last_snippet == snippet {
// No new lines in the snippet.
this.buffer.push_str("\n");
}
let indent = make_indent(this.block_indent);
this.buffer.push_str(&indent);
})
this.buffer.push_str("\n");
}
let indent = make_indent(this.block_indent);
this.buffer.push_str(&indent);
})
}
fn format_missing_inner<F: Fn(&mut FmtVisitor, &str, &str)>(&mut self,
@ -60,9 +59,7 @@ impl<'a> FmtVisitor<'a> {
let span = codemap::mk_sp(start, end);
let snippet = self.snippet(span);
self.write_snippet(&snippet,
true,
&process_last_snippet);
self.write_snippet(&snippet, true, &process_last_snippet);
}
fn write_snippet<F: Fn(&mut FmtVisitor, &str, &str)>(&mut self,

View File

@ -44,8 +44,8 @@ pub fn rewrite_string<'a>(s: &str, fmt: &StringFormat<'a>) -> String {
result.push_str(fmt.opener);
let ender_length = fmt.line_end.len();
let max_chars = fmt.width.checked_sub(fmt.opener.len()).unwrap_or(0)
.checked_sub(ender_length).unwrap_or(1);
let max_chars = fmt.width.checked_sub(fmt.opener.len() + ender_length).unwrap_or(1);
loop {
let mut cur_end = cur_start + max_chars;

View File

@ -196,13 +196,12 @@ fn rewrite_segment(segment: &ast::PathSegment,
ast::PathParameters::AngleBracketedParameters(ref data) if !data.lifetimes.is_empty() ||
!data.types.is_empty() ||
!data.bindings.is_empty() => {
let param_list = data.lifetimes.iter()
.map(SegmentParam::LifeTime)
.chain(data.types.iter()
.map(|x| SegmentParam::Type(&*x)))
.chain(data.bindings.iter()
.map(|x| SegmentParam::Binding(&*x)))
.collect::<Vec<_>>();
let param_list = data.lifetimes
.iter()
.map(SegmentParam::LifeTime)
.chain(data.types.iter().map(|x| SegmentParam::Type(&*x)))
.chain(data.bindings.iter().map(|x| SegmentParam::Binding(&*x)))
.collect::<Vec<_>>();
let next_span_lo = param_list.last().unwrap().get_span().hi + BytePos(1);
let list_lo = span_after(codemap::mk_sp(*span_lo, span_hi), "<", context.codemap);
@ -279,30 +278,27 @@ impl Rewrite for ast::WherePredicate {
ref bounds,
..}) => {
if !bound_lifetimes.is_empty() {
let lifetime_str = bound_lifetimes.iter().map(|lt| {
lt.rewrite(context, width, offset).unwrap()
}).collect::<Vec<_>>().join(", ");
let lifetime_str = bound_lifetimes.iter()
.map(|lt| lt.rewrite(context, width, offset).unwrap())
.collect::<Vec<_>>()
.join(", ");
let type_str = pprust::ty_to_string(bounded_ty);
// 8 = "for<> : ".len()
let used_width = lifetime_str.len() + type_str.len() + 8;
let bounds_str = bounds.iter().map(|ty_bound| {
ty_bound.rewrite(context,
width - used_width,
offset + used_width)
.unwrap()
}).collect::<Vec<_>>().join(" + ");
let bounds_str = bounds.iter()
.map(|ty_bound| ty_bound.rewrite(context, width - used_width, offset + used_width).unwrap())
.collect::<Vec<_>>()
.join(" + ");
format!("for<{}> {}: {}", lifetime_str, type_str, bounds_str)
} else {
let type_str = pprust::ty_to_string(bounded_ty);
// 2 = ": ".len()
let used_width = type_str.len() + 2;
let bounds_str = bounds.iter().map(|ty_bound| {
ty_bound.rewrite(context,
width - used_width,
offset + used_width)
.unwrap()
}).collect::<Vec<_>>().join(" + ");
let bounds_str = bounds.iter()
.map(|ty_bound| ty_bound.rewrite(context, width - used_width, offset + used_width).unwrap())
.collect::<Vec<_>>()
.join(" + ");
format!("{}: {}", type_str, bounds_str)
}
@ -373,9 +369,11 @@ impl Rewrite for ast::TyParam {
if !self.bounds.is_empty() {
result.push_str(": ");
let bounds = self.bounds.iter().map(|ty_bound| {
ty_bound.rewrite(context, width, offset).unwrap()
}).collect::<Vec<_>>().join(" + ");
let bounds = self.bounds
.iter()
.map(|ty_bound| ty_bound.rewrite(context, width, offset).unwrap())
.collect::<Vec<_>>()
.join(" + ");
result.push_str(&bounds);
}
@ -392,9 +390,11 @@ impl Rewrite for ast::TyParam {
impl Rewrite for ast::PolyTraitRef {
fn rewrite(&self, context: &RewriteContext, width: usize, offset: usize) -> Option<String> {
if !self.bound_lifetimes.is_empty() {
let lifetime_str = self.bound_lifetimes.iter().map(|lt| {
lt.rewrite(context, width, offset).unwrap()
}).collect::<Vec<_>>().join(", ");
let lifetime_str = self.bound_lifetimes
.iter()
.map(|lt| lt.rewrite(context, width, offset).unwrap())
.collect::<Vec<_>>()
.join(", ");
// 6 is "for<> ".len()
let extra_offset = lifetime_str.len() + 6;
let max_path_width = try_opt!(width.checked_sub(extra_offset));

View File

@ -14,6 +14,7 @@ use syntax::ast::{self, Visibility, Attribute, MetaItem, MetaItem_};
use syntax::codemap::{CodeMap, Span, BytePos};
use comment::FindUncommented;
use rewrite::{Rewrite, RewriteContext};
use SKIP_ANNOTATION;
@ -93,10 +94,16 @@ pub fn contains_skip(attrs: &[Attribute]) -> bool {
// Find the end of a TyParam
#[inline]
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
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]
@ -202,6 +209,13 @@ pub fn wrap_str<S: AsRef<str>>(s: S, max_width: usize, width: usize, offset: usi
Some(s)
}
impl Rewrite for String {
fn rewrite(&self, context: &RewriteContext, width: usize, offset: usize) -> Option<String> {
// FIXME: unnecessary clone
wrap_str(self.clone(), context.config.max_width, width, offset)
}
}
// Binary search in integer range. Returns the first Ok value returned by the
// callback.
// The callback takes an integer and returns either an Ok, or an Err indicating

View File

@ -202,19 +202,11 @@ impl<'a, 'v> visit::Visitor<'v> for FmtVisitor<'a> {
}
ast::Item_::ItemStruct(ref def, ref generics) => {
self.format_missing_with_indent(item.span.lo);
self.visit_struct(item.ident,
item.vis,
def,
generics,
item.span);
self.visit_struct(item.ident, item.vis, def, generics, item.span);
}
ast::Item_::ItemEnum(ref def, ref generics) => {
self.format_missing_with_indent(item.span.lo);
self.visit_enum(item.ident,
item.vis,
def,
generics,
item.span);
self.visit_enum(item.ident, item.vis, def, generics, item.span);
self.last_pos = item.span.hi;
}
ast::Item_::ItemMod(ref module) => {
@ -236,10 +228,7 @@ impl<'a, 'v> visit::Visitor<'v> for FmtVisitor<'a> {
self.format_missing_with_indent(ti.span.lo);
let indent = self.block_indent;
let new_fn = self.rewrite_required_fn(indent,
ti.ident,
sig,
ti.span);
let new_fn = self.rewrite_required_fn(indent, ti.ident, sig, ti.span);
if let Some(fn_str) = new_fn {
@ -299,10 +288,9 @@ impl<'a> FmtVisitor<'a> {
if utils::contains_skip(attrs) {
true
} else {
let rewrite = attrs.rewrite(&self.get_context(),
self.config.max_width - self.block_indent,
self.block_indent)
.unwrap();
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;

View File

@ -120,10 +120,8 @@ pub fn idempotent_check(filename: String) -> Result<(), HashMap<String, Vec<Mism
// panic to return a result in case of failure. This has the advantage of smoothing the road to
// multithreaded rustfmt
thread::catch_panic(move || {
run(args, WriteMode::Return(HANDLE_RESULT), config);
}).map_err(|any|
*any.downcast().ok().expect("Downcast failed.")
)
run(args, WriteMode::Return(HANDLE_RESULT), config);
}).map_err(|any| *any.downcast().ok().expect("Downcast failed."))
}
@ -154,19 +152,21 @@ fn read_significant_comments(file_name: &str) -> HashMap<String, String> {
let regex = regex::Regex::new(&pattern).ok().expect("Failed creating pattern 1.");
// Matches lines containing significant comments or whitespace.
let line_regex = regex::Regex::new(r"(^\s*$)|(^\s*//\s*rustfmt-[^:]+:\s*\S+)")
.ok().expect("Failed creating pattern 2.");
let line_regex = regex::Regex::new(r"(^\s*$)|(^\s*//\s*rustfmt-[^:]+:\s*\S+)").ok()
.expect("Failed creating pattern 2.");
reader.lines()
.map(|line| line.ok().expect("Failed getting line."))
.take_while(|line| line_regex.is_match(&line))
.filter_map(|line| {
regex.captures_iter(&line).next().map(|capture| {
(capture.at(1).expect("Couldn't unwrap capture.").to_owned(),
capture.at(2).expect("Couldn't unwrap capture.").to_owned())
})
})
.collect()
.map(|line| line.ok().expect("Failed getting line."))
.take_while(|line| line_regex.is_match(&line))
.filter_map(|line| {
regex.captures_iter(&line)
.next()
.map(|capture| {
(capture.at(1).expect("Couldn't unwrap capture.").to_owned(),
capture.at(2).expect("Couldn't unwrap capture.").to_owned())
})
})
.collect()
}
// Compare output to input.