Use block indent for tuple pattern when fn_call_style is Block

This commit is contained in:
topecongiro 2017-06-15 16:25:40 +09:00
parent bd1eff55bb
commit a5138b1676
3 changed files with 196 additions and 95 deletions

View File

@ -25,10 +25,11 @@ use utils::{extra_offset, last_line_width, wrap_str, binary_search, first_line_w
use visitor::FmtVisitor; use visitor::FmtVisitor;
use config::{Config, IndentStyle, MultilineStyle, ControlBraceStyle, Style}; use config::{Config, IndentStyle, MultilineStyle, ControlBraceStyle, Style};
use comment::{FindUncommented, rewrite_comment, contains_comment, recover_comment_removed}; use comment::{FindUncommented, rewrite_comment, contains_comment, recover_comment_removed};
use types::{rewrite_path, PathContext}; use types::{rewrite_path, PathContext, can_be_overflowed_type};
use items::{span_lo_for_arg, span_hi_for_arg}; use items::{span_lo_for_arg, span_hi_for_arg};
use chains::rewrite_chain; use chains::rewrite_chain;
use macros::{rewrite_macro, MacroPosition}; use macros::{rewrite_macro, MacroPosition};
use patterns::{TuplePatField, can_be_overflowed_pat};
use syntax::{ast, ptr}; use syntax::{ast, ptr};
use syntax::codemap::{CodeMap, Span, BytePos}; use syntax::codemap::{CodeMap, Span, BytePos};
@ -110,7 +111,13 @@ fn format_expr(
} }
ast::ExprKind::Call(ref callee, ref args) => { ast::ExprKind::Call(ref callee, ref args) => {
let inner_span = mk_sp(callee.span.hi, expr.span.hi); let inner_span = mk_sp(callee.span.hi, expr.span.hi);
rewrite_call_with_binary_search(context, &**callee, args, inner_span, shape) rewrite_call_with_binary_search(
context,
&**callee,
&args.iter().map(|x| &**x).collect::<Vec<_>>()[..],
inner_span,
shape,
)
} }
ast::ExprKind::Paren(ref subexpr) => rewrite_paren(context, subexpr, shape), ast::ExprKind::Paren(ref subexpr) => rewrite_paren(context, subexpr, shape),
ast::ExprKind::Binary(ref op, ref lhs, ref rhs) => { ast::ExprKind::Binary(ref op, ref lhs, ref rhs) => {
@ -136,7 +143,14 @@ fn format_expr(
shape, shape,
) )
} }
ast::ExprKind::Tup(ref items) => rewrite_tuple(context, items, expr.span, shape), ast::ExprKind::Tup(ref items) => {
rewrite_tuple(
context,
&items.iter().map(|x| &**x).collect::<Vec<_>>()[..],
expr.span,
shape,
)
}
ast::ExprKind::While(ref cond, ref block, label) => { ast::ExprKind::While(ref cond, ref block, label) => {
ControlFlow::new_while(None, cond, block, label, expr.span).rewrite(context, shape) ControlFlow::new_while(None, cond, block, label, expr.span).rewrite(context, shape)
} }
@ -1800,7 +1814,7 @@ fn string_requires_rewrite(
pub fn rewrite_call_with_binary_search<R>( pub fn rewrite_call_with_binary_search<R>(
context: &RewriteContext, context: &RewriteContext,
callee: &R, callee: &R,
args: &[ptr::P<ast::Expr>], args: &[&ast::Expr],
span: Span, span: Span,
shape: Shape, shape: Shape,
) -> Option<String> ) -> Option<String>
@ -1818,7 +1832,15 @@ where
Ordering::Greater, Ordering::Greater,
)?; )?;
rewrite_call_inner(context, &callee_str, args, span, shape, false) rewrite_call_inner(
context,
&callee_str,
args,
span,
shape,
context.config.fn_call_width(),
false,
)
}; };
binary_search(1, shape.width, closure) binary_search(1, shape.width, closure)
@ -1831,15 +1853,24 @@ pub fn rewrite_call(
span: Span, span: Span,
shape: Shape, shape: Shape,
) -> Option<String> { ) -> Option<String> {
rewrite_call_inner(context, &callee, args, span, shape, false).ok() rewrite_call_inner(
context,
&callee,
&args.iter().map(|x| &**x).collect::<Vec<_>>(),
span,
shape,
context.config.fn_call_width(),
false,
).ok()
} }
fn rewrite_call_inner<'a, T>( pub fn rewrite_call_inner<'a, T>(
context: &RewriteContext, context: &RewriteContext,
callee_str: &str, callee_str: &str,
args: &[ptr::P<T>], args: &[&T],
span: Span, span: Span,
shape: Shape, shape: Shape,
args_max_width: usize,
force_trailing_comma: bool, force_trailing_comma: bool,
) -> Result<String, Ordering> ) -> Result<String, Ordering>
where where
@ -1873,6 +1904,7 @@ where
args_span, args_span,
nested_shape, nested_shape,
one_line_width, one_line_width,
args_max_width,
force_trailing_comma, force_trailing_comma,
).or_else(|| if context.use_block_indent() { ).or_else(|| if context.use_block_indent() {
rewrite_call_args( rewrite_call_args(
@ -1884,6 +1916,7 @@ where
context.config, context.config,
), ),
0, 0,
0,
force_trailing_comma, force_trailing_comma,
) )
} else { } else {
@ -1900,6 +1933,7 @@ where
args, args,
span, span,
shape, shape,
args_max_width,
force_trailing_comma, force_trailing_comma,
); );
} }
@ -1930,10 +1964,11 @@ fn need_block_indent(s: &str, shape: Shape) -> bool {
fn rewrite_call_args<'a, T>( fn rewrite_call_args<'a, T>(
context: &RewriteContext, context: &RewriteContext,
args: &[ptr::P<T>], args: &[&T],
span: Span, span: Span,
shape: Shape, shape: Shape,
one_line_width: usize, one_line_width: usize,
args_max_width: usize,
force_trailing_comma: bool, force_trailing_comma: bool,
) -> Option<(bool, String)> ) -> Option<(bool, String)>
where where
@ -1956,13 +1991,13 @@ where
// Try letting the last argument overflow to the next line with block // Try letting the last argument overflow to the next line with block
// indentation. If its first line fits on one line with the other arguments, // indentation. If its first line fits on one line with the other arguments,
// we format the function arguments horizontally. // we format the function arguments horizontally.
let args = args.iter().filter_map(|e| e.to_expr()).collect::<Vec<_>>();
let tactic = try_overflow_last_arg( let tactic = try_overflow_last_arg(
&item_context, &item_context,
&mut item_vec, &mut item_vec,
&args[..], &args[..],
shape, shape,
one_line_width, one_line_width,
args_max_width,
); );
let fmt = ListFormatting { let fmt = ListFormatting {
@ -1985,38 +2020,45 @@ where
}) })
} }
fn try_overflow_last_arg( fn try_overflow_last_arg<'a, T>(
context: &RewriteContext, context: &RewriteContext,
item_vec: &mut Vec<ListItem>, item_vec: &mut Vec<ListItem>,
args: &[&ast::Expr], args: &[&T],
shape: Shape, shape: Shape,
one_line_width: usize, one_line_width: usize,
) -> DefinitiveListTactic { args_max_width: usize,
) -> DefinitiveListTactic
where
T: Rewrite + Spanned + ToExpr + 'a,
{
let overflow_last = can_be_overflowed(&context, args); let overflow_last = can_be_overflowed(&context, args);
// Replace the last item with its first line to see if it fits with // Replace the last item with its first line to see if it fits with
// first arguments. // first arguments.
let (orig_last, placeholder) = if overflow_last { let (orig_last, placeholder) = if overflow_last {
let mut context = context.clone(); let mut context = context.clone();
match args[args.len() - 1].node { if let Some(expr) = args[args.len() - 1].to_expr() {
ast::ExprKind::MethodCall(..) => context.force_one_line_chain = true, match expr.node {
_ => (), ast::ExprKind::MethodCall(..) => context.force_one_line_chain = true,
_ => (),
}
} }
last_arg_shape(&context, &item_vec, shape).map_or((None, None), |arg_shape| { last_arg_shape(&context, &item_vec, shape, args_max_width)
rewrite_last_arg_with_overflow( .map_or((None, None), |arg_shape| {
&context, rewrite_last_arg_with_overflow(
args[args.len() - 1], &context,
&mut item_vec[args.len() - 1], args[args.len() - 1],
arg_shape, &mut item_vec[args.len() - 1],
) arg_shape,
}) )
})
} else { } else {
(None, None) (None, None)
}; };
let tactic = definitive_tactic( let tactic = definitive_tactic(
&*item_vec, &*item_vec,
ListTactic::LimitedHorizontalVertical(context.config.fn_call_width()), ListTactic::LimitedHorizontalVertical(args_max_width),
one_line_width, one_line_width,
); );
@ -2035,11 +2077,16 @@ fn try_overflow_last_arg(
tactic tactic
} }
fn last_arg_shape(context: &RewriteContext, items: &Vec<ListItem>, shape: Shape) -> Option<Shape> { fn last_arg_shape(
context: &RewriteContext,
items: &Vec<ListItem>,
shape: Shape,
args_max_width: usize,
) -> Option<Shape> {
let overhead = items.iter().rev().skip(1).fold(0, |acc, i| { let overhead = items.iter().rev().skip(1).fold(0, |acc, i| {
acc + i.item.as_ref().map_or(0, |s| first_line_width(&s)) acc + i.item.as_ref().map_or(0, |s| first_line_width(&s))
}); });
let max_width = min(context.config.fn_call_width(), shape.width); let max_width = min(args_max_width, shape.width);
let arg_indent = if context.use_block_indent() { let arg_indent = if context.use_block_indent() {
shape.block().indent.block_unindent(context.config) shape.block().indent.block_unindent(context.config)
} else { } else {
@ -2052,12 +2099,15 @@ fn last_arg_shape(context: &RewriteContext, items: &Vec<ListItem>, shape: Shape)
}) })
} }
fn rewrite_last_arg_with_overflow( fn rewrite_last_arg_with_overflow<'a, T>(
context: &RewriteContext, context: &RewriteContext,
last_arg: &ast::Expr, last_arg: &T,
last_item: &mut ListItem, last_item: &mut ListItem,
shape: Shape, shape: Shape,
) -> (Option<String>, Option<String>) { ) -> (Option<String>, Option<String>)
where
T: Rewrite + Spanned + ToExpr + 'a,
{
let rewrite = last_arg.rewrite(context, shape); let rewrite = last_arg.rewrite(context, shape);
let orig_last = last_item.item.clone(); let orig_last = last_item.item.clone();
@ -2070,13 +2120,17 @@ fn rewrite_last_arg_with_overflow(
} }
} }
fn can_be_overflowed(context: &RewriteContext, args: &[&ast::Expr]) -> bool { fn can_be_overflowed<'a, T>(context: &RewriteContext, args: &[&T]) -> bool
args.last().map_or(false, |x| { where
can_be_overflowed_expr(context, &x, args.len()) T: Rewrite + Spanned + ToExpr + 'a,
}) {
args.last().map_or(
false,
|x| x.can_be_overflowed(context, args.len()),
)
} }
fn can_be_overflowed_expr(context: &RewriteContext, expr: &ast::Expr, args_len: usize) -> bool { pub fn can_be_overflowed_expr(context: &RewriteContext, expr: &ast::Expr, args_len: usize) -> bool {
match expr.node { match expr.node {
ast::ExprKind::Match(..) => { ast::ExprKind::Match(..) => {
(context.use_block_indent() && args_len == 1) || (context.use_block_indent() && args_len == 1) ||
@ -2117,7 +2171,7 @@ fn paren_overhead(context: &RewriteContext) -> usize {
} }
} }
fn wrap_args_with_parens( pub fn wrap_args_with_parens(
context: &RewriteContext, context: &RewriteContext,
args_str: &str, args_str: &str,
is_extendable: bool, is_extendable: bool,
@ -2370,7 +2424,7 @@ fn shape_from_fn_call_style(
fn rewrite_tuple_in_visual_indent_style<'a, T>( fn rewrite_tuple_in_visual_indent_style<'a, T>(
context: &RewriteContext, context: &RewriteContext,
items: &[ptr::P<T>], items: &[&T],
span: Span, span: Span,
shape: Shape, shape: Shape,
) -> Option<String> ) -> Option<String>
@ -2417,7 +2471,7 @@ where
pub fn rewrite_tuple<'a, T>( pub fn rewrite_tuple<'a, T>(
context: &RewriteContext, context: &RewriteContext,
items: &[ptr::P<T>], items: &[&T],
span: Span, span: Span,
shape: Shape, shape: Shape,
) -> Option<String> ) -> Option<String>
@ -2433,6 +2487,7 @@ where
items, items,
span, span,
shape, shape,
context.config.fn_call_width(),
items.len() == 1, items.len() == 1,
).ok() ).ok()
} else { } else {
@ -2590,16 +2645,35 @@ fn rewrite_expr_addrof(
pub trait ToExpr { pub trait ToExpr {
fn to_expr(&self) -> Option<&ast::Expr>; fn to_expr(&self) -> Option<&ast::Expr>;
fn can_be_overflowed(&self, context: &RewriteContext, len: usize) -> bool;
} }
impl ToExpr for ast::Expr { impl ToExpr for ast::Expr {
fn to_expr(&self) -> Option<&ast::Expr> { fn to_expr(&self) -> Option<&ast::Expr> {
Some(self) Some(self)
} }
fn can_be_overflowed(&self, context: &RewriteContext, len: usize) -> bool {
can_be_overflowed_expr(context, self, len)
}
} }
impl ToExpr for ast::Ty { impl ToExpr for ast::Ty {
fn to_expr(&self) -> Option<&ast::Expr> { fn to_expr(&self) -> Option<&ast::Expr> {
None None
} }
fn can_be_overflowed(&self, context: &RewriteContext, len: usize) -> bool {
can_be_overflowed_type(context, self, len)
}
}
impl<'a> ToExpr for TuplePatField<'a> {
fn to_expr(&self) -> Option<&ast::Expr> {
None
}
fn can_be_overflowed(&self, context: &RewriteContext, len: usize) -> bool {
can_be_overflowed_pat(context, self, len)
}
} }

View File

@ -13,10 +13,9 @@ use codemap::SpanUtils;
use config::{IndentStyle, MultilineStyle}; use config::{IndentStyle, MultilineStyle};
use rewrite::{Rewrite, RewriteContext}; use rewrite::{Rewrite, RewriteContext};
use utils::{wrap_str, format_mutability, mk_sp}; use utils::{wrap_str, format_mutability, mk_sp};
use lists::{DefinitiveListTactic, SeparatorTactic, format_item_list, itemize_list, ListItem, use lists::{DefinitiveListTactic, SeparatorTactic, itemize_list, struct_lit_shape,
struct_lit_shape, struct_lit_tactic, shape_for_tactic, struct_lit_formatting, struct_lit_tactic, shape_for_tactic, struct_lit_formatting, write_list};
write_list}; use expr::{rewrite_call_inner, rewrite_unary_prefix, rewrite_pair, can_be_overflowed_expr};
use expr::{rewrite_unary_prefix, rewrite_pair};
use types::{rewrite_path, PathContext}; use types::{rewrite_path, PathContext};
use super::Spanned; use super::Spanned;
use comment::FindUncommented; use comment::FindUncommented;
@ -239,7 +238,7 @@ impl Rewrite for FieldPat {
} }
} }
enum TuplePatField<'a> { pub enum TuplePatField<'a> {
Pat(&'a ptr::P<ast::Pat>), Pat(&'a ptr::P<ast::Pat>),
Dotdot(Span), Dotdot(Span),
} }
@ -262,6 +261,24 @@ impl<'a> Spanned for TuplePatField<'a> {
} }
} }
pub fn can_be_overflowed_pat(context: &RewriteContext, pat: &TuplePatField, len: usize) -> bool {
match pat {
&TuplePatField::Pat(ref pat) => {
match pat.node {
ast::PatKind::Tuple(..) |
ast::PatKind::Struct(..) => context.use_block_indent() && len == 1,
ast::PatKind::Ref(ref p, _) |
ast::PatKind::Box(ref p) => {
can_be_overflowed_pat(context, &TuplePatField::Pat(p), len)
}
ast::PatKind::Lit(ref expr) => can_be_overflowed_expr(context, expr, len),
_ => false,
}
}
&TuplePatField::Dotdot(..) => false,
}
}
fn rewrite_tuple_pat( fn rewrite_tuple_pat(
pats: &[ptr::P<ast::Pat>], pats: &[ptr::P<ast::Pat>],
dotdot_pos: Option<usize>, dotdot_pos: Option<usize>,
@ -286,77 +303,73 @@ fn rewrite_tuple_pat(
let dot_span = mk_sp(prev, next); let dot_span = mk_sp(prev, next);
let snippet = context.snippet(dot_span); let snippet = context.snippet(dot_span);
let lo = dot_span.lo + BytePos(snippet.find_uncommented("..").unwrap() as u32); let lo = dot_span.lo + BytePos(snippet.find_uncommented("..").unwrap() as u32);
let span = Span { let dotdot = TuplePatField::Dotdot(Span {
lo: lo, lo: lo,
// 2 == "..".len() // 2 == "..".len()
hi: lo + BytePos(2), hi: lo + BytePos(2),
ctxt: codemap::NO_EXPANSION, ctxt: codemap::NO_EXPANSION,
}; });
let dotdot = TuplePatField::Dotdot(span);
pat_vec.insert(pos, dotdot); pat_vec.insert(pos, dotdot);
} }
if pat_vec.is_empty() { if pat_vec.is_empty() {
return Some(format!("{}()", try_opt!(path_str))); return Some(format!("{}()", try_opt!(path_str)));
} }
let wildcard_suffix_len = count_wildcard_suffix_len(context, &pat_vec, span, shape);
let (pat_vec, span) =
if context.config.condense_wildcard_suffixes() && wildcard_suffix_len >= 2 {
let new_item_count = 1 + pat_vec.len() - wildcard_suffix_len;
let sp = pat_vec[new_item_count - 1].span();
let snippet = context.snippet(sp);
let lo = sp.lo + BytePos(snippet.find_uncommented("_").unwrap() as u32);
pat_vec[new_item_count - 1] = TuplePatField::Dotdot(mk_sp(lo, lo + BytePos(1)));
(&pat_vec[..new_item_count], mk_sp(span.lo, lo + BytePos(1)))
} else {
(&pat_vec[..], span)
};
// add comma if `(x,)` // add comma if `(x,)`
let add_comma = path_str.is_none() && pat_vec.len() == 1 && dotdot_pos.is_none(); let add_comma = path_str.is_none() && pat_vec.len() == 1 && dotdot_pos.is_none();
let mut context = context.clone();
if let Some(&TuplePatField::Dotdot(..)) = pat_vec.last() {
context.inside_macro = true;
}
let path_str = path_str.unwrap_or(String::new());
let mut pat_ref_vec = Vec::with_capacity(pat_vec.len());
for pat in pat_vec {
pat_ref_vec.push(pat);
}
return rewrite_call_inner(
&context,
&path_str,
&pat_ref_vec[..],
span,
shape,
shape.width,
add_comma,
).ok();
}
let path_len = path_str.as_ref().map(|p| p.len()).unwrap_or(0); fn count_wildcard_suffix_len(
// 2 = "()".len(), 3 = "(,)".len() context: &RewriteContext,
let nested_shape = try_opt!(shape.sub_width(path_len + if add_comma { 3 } else { 2 })); patterns: &[TuplePatField],
// 1 = "(".len() span: Span,
let nested_shape = nested_shape.visual_indent(path_len + 1); shape: Shape,
let mut items: Vec<_> = itemize_list( ) -> usize {
let mut suffix_len = 0;
let items: Vec<_> = itemize_list(
context.codemap, context.codemap,
pat_vec.iter(), patterns.iter(),
if add_comma { ",)" } else { ")" }, ")",
|item| item.span().lo, |item| item.span().lo,
|item| item.span().hi, |item| item.span().hi,
|item| item.rewrite(context, nested_shape), |item| item.rewrite(context, shape),
context.codemap.span_after(span, "("), context.codemap.span_after(span, "("),
span.hi - BytePos(1), span.hi - BytePos(1),
).collect(); ).collect();
// Condense wildcard string suffix into a single ..
let wildcard_suffix_len = count_wildcard_suffix_len(&items);
let list = if context.config.condense_wildcard_suffixes() && wildcard_suffix_len >= 2 {
let new_item_count = 1 + pats.len() - wildcard_suffix_len;
items[new_item_count - 1].item = Some("..".to_owned());
let da_iter = items.into_iter().take(new_item_count);
try_opt!(format_item_list(da_iter, nested_shape, context.config))
} else {
try_opt!(format_item_list(
items.into_iter(),
nested_shape,
context.config,
))
};
match path_str {
Some(path_str) => {
Some(if context.config.spaces_within_parens() {
format!("{}( {} )", path_str, list)
} else {
format!("{}({})", path_str, list)
})
}
None => {
let comma = if add_comma { "," } else { "" };
Some(if context.config.spaces_within_parens() {
format!("( {}{} )", list, comma)
} else {
format!("({}{})", list, comma)
})
}
}
}
fn count_wildcard_suffix_len(items: &[ListItem]) -> usize {
let mut suffix_len = 0;
for item in items.iter().rev().take_while(|i| match i.item { for item in items.iter().rev().take_while(|i| match i.item {
Some(ref internal_string) if internal_string == "_" => true, Some(ref internal_string) if internal_string == "_" => true,
_ => false, _ => false,

View File

@ -689,7 +689,14 @@ impl Rewrite for ast::Ty {
format!("[{}]", ty_str) format!("[{}]", ty_str)
}) })
} }
ast::TyKind::Tup(ref items) => rewrite_tuple(context, items, self.span, shape), ast::TyKind::Tup(ref items) => {
rewrite_tuple(
context,
&items.iter().map(|x| &**x).collect::<Vec<_>>()[..],
self.span,
shape,
)
}
ast::TyKind::Path(ref q_self, ref path) => { ast::TyKind::Path(ref q_self, ref path) => {
rewrite_path(context, PathContext::Type, q_self.as_ref(), path, shape) rewrite_path(context, PathContext::Type, q_self.as_ref(), path, shape)
} }
@ -792,3 +799,10 @@ pub fn join_bounds(context: &RewriteContext, shape: Shape, type_strs: &Vec<Strin
result result
} }
} }
pub fn can_be_overflowed_type(context: &RewriteContext, ty: &ast::Ty, len: usize) -> bool {
match ty.node {
ast::TyKind::Tup(..) => context.use_block_indent() && len == 1,
_ => false,
}
}