X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fexpr.rs;h=72cf618dca546fc7c0213013d2340ec4dd989161;hb=caefd218c9f6c43493c28c5cc4ea8828c494830e;hp=7ca74c6ef0e55f48f5b37a830cc47245a63aaa72;hpb=43890cff6b8e1a93d8d6c4189af7b0fbeb70eab7;p=rust.git diff --git a/src/expr.rs b/src/expr.rs index 7ca74c6ef0e..72cf618dca5 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -19,23 +19,30 @@ use chains::rewrite_chain; use closures; use codemap::{LineRangeUtils, SpanUtils}; -use comment::{combine_strs_with_missing_comments, contains_comment, recover_comment_removed, - rewrite_comment, rewrite_missing_comment, CharClasses, FindUncommented}; +use comment::{ + combine_strs_with_missing_comments, contains_comment, recover_comment_removed, rewrite_comment, + rewrite_missing_comment, CharClasses, FindUncommented, +}; use config::{Config, ControlBraceStyle, IndentStyle}; -use lists::{definitive_tactic, itemize_list, shape_for_tactic, struct_lit_formatting, - struct_lit_shape, struct_lit_tactic, write_list, ListFormatting, ListItem, Separator}; +use lists::{ + definitive_tactic, itemize_list, shape_for_tactic, struct_lit_formatting, struct_lit_shape, + struct_lit_tactic, write_list, ListFormatting, ListItem, Separator, +}; use macros::{rewrite_macro, MacroArg, MacroPosition}; use matches::rewrite_match; use overflow; +use pairs::{rewrite_all_pairs, rewrite_pair, PairParts}; use patterns::{can_be_overflowed_pat, is_short_pattern, TuplePatField}; use rewrite::{Rewrite, RewriteContext}; use shape::{Indent, Shape}; use spanned::Spanned; use string::{rewrite_string, StringFormat}; use types::{can_be_overflowed_type, rewrite_path, PathContext}; -use utils::{colon_spaces, contains_skip, count_newlines, first_line_width, inner_attributes, - last_line_extendable, last_line_width, mk_sp, outer_attributes, paren_overhead, - ptr_vec_to_ref_vec, semicolon_for_stmt, wrap_str}; +use utils::{ + colon_spaces, contains_skip, count_newlines, first_line_ends_with, first_line_width, + inner_attributes, last_line_extendable, last_line_width, mk_sp, outer_attributes, + ptr_vec_to_ref_vec, semicolon_for_stmt, wrap_str, +}; use vertical::rewrite_with_alignment; use visitor::FmtVisitor; @@ -80,16 +87,18 @@ pub fn format_expr( rewrite_call(context, &callee_str, args, inner_span, shape) } ast::ExprKind::Paren(ref subexpr) => rewrite_paren(context, subexpr, shape, expr.span), - ast::ExprKind::Binary(ref op, ref lhs, ref rhs) => { + ast::ExprKind::Binary(op, ref lhs, ref rhs) => { // FIXME: format comments between operands and operator - rewrite_pair( - &**lhs, - &**rhs, - PairParts::new("", &format!(" {} ", context.snippet(op.span)), ""), - context, - shape, - context.config.binop_separator(), - ) + rewrite_all_pairs(expr, shape, context).or_else(|| { + rewrite_pair( + &**lhs, + &**rhs, + PairParts::infix(&format!(" {} ", context.snippet(op.span))), + context, + shape, + context.config.binop_separator(), + ) + }) } ast::ExprKind::Unary(ref op, ref subexpr) => rewrite_unary_op(context, op, subexpr, shape), ast::ExprKind::Struct(ref path, ref fields, ref base) => rewrite_struct_lit( @@ -110,29 +119,33 @@ pub fn format_expr( | ast::ExprKind::While(..) | ast::ExprKind::WhileLet(..) => to_control_flow(expr, expr_type) .and_then(|control_flow| control_flow.rewrite(context, shape)), - ast::ExprKind::Block(ref block) => { + ast::ExprKind::Block(ref block, opt_label) => { match expr_type { ExprType::Statement => { if is_unsafe_block(block) { - rewrite_block(block, Some(&expr.attrs), context, shape) + rewrite_block(block, Some(&expr.attrs), opt_label, context, shape) } else if let rw @ Some(_) = - rewrite_empty_block(context, block, Some(&expr.attrs), "", shape) + rewrite_empty_block(context, block, Some(&expr.attrs), opt_label, "", shape) { // Rewrite block without trying to put it in a single line. rw } else { let prefix = block_prefix(context, block, shape)?; + rewrite_block_with_visitor( context, &prefix, block, Some(&expr.attrs), + opt_label, shape, true, ) } } - ExprType::SubExpression => rewrite_block(block, Some(&expr.attrs), context, shape), + ExprType::SubExpression => { + rewrite_block(block, Some(&expr.attrs), opt_label, context, shape) + } } } ast::ExprKind::Match(ref cond, ref arms) => { @@ -171,9 +184,9 @@ pub fn format_expr( } else { Some("yield".to_string()) }, - ast::ExprKind::Closure(capture, movability, ref fn_decl, ref body, _) => { + ast::ExprKind::Closure(capture, asyncness, movability, ref fn_decl, ref body, _) => { closures::rewrite_closure( - capture, movability, fn_decl, body, expr.span, context, shape, + capture, asyncness, movability, fn_decl, body, expr.span, context, shape, ) } ast::ExprKind::Try(..) | ast::ExprKind::Field(..) | ast::ExprKind::MethodCall(..) => { @@ -199,7 +212,7 @@ pub fn format_expr( ast::ExprKind::Cast(ref expr, ref ty) => rewrite_pair( &**expr, &**ty, - PairParts::new("", " as ", ""), + PairParts::infix(" as "), context, shape, SeparatorPlace::Front, @@ -207,7 +220,7 @@ pub fn format_expr( ast::ExprKind::Type(ref expr, ref ty) => rewrite_pair( &**expr, &**ty, - PairParts::new("", ": ", ""), + PairParts::infix(": "), context, shape, SeparatorPlace::Back, @@ -215,21 +228,14 @@ pub fn format_expr( ast::ExprKind::Index(ref expr, ref index) => { rewrite_index(&**expr, &**index, context, shape) } - ast::ExprKind::Repeat(ref expr, ref repeats) => { - let (lbr, rbr) = if context.config.spaces_within_parens_and_brackets() { - ("[ ", " ]") - } else { - ("[", "]") - }; - rewrite_pair( - &**expr, - &**repeats, - PairParts::new(lbr, "; ", rbr), - context, - shape, - SeparatorPlace::Back, - ) - } + ast::ExprKind::Repeat(ref expr, ref repeats) => rewrite_pair( + &**expr, + &*repeats.value, + PairParts::new("[", "; ", "]"), + context, + shape, + SeparatorPlace::Back, + ), ast::ExprKind::Range(ref lhs, ref rhs, limits) => { let delim = match limits { ast::RangeLimits::HalfOpen => "..", @@ -283,7 +289,7 @@ fn needs_space_after_range(rhs: &ast::Expr) -> bool { rewrite_pair( &*lhs, &*rhs, - PairParts::new("", &sp_delim, ""), + PairParts::infix(&sp_delim), context, shape, context.config.binop_separator(), @@ -312,19 +318,59 @@ fn needs_space_after_range(rhs: &ast::Expr) -> bool { // satisfy our width restrictions. ast::ExprKind::InlineAsm(..) => Some(context.snippet(expr.span).to_owned()), ast::ExprKind::Catch(ref block) => { - if let rw @ Some(_) = - rewrite_single_line_block(context, "do catch ", block, Some(&expr.attrs), shape) - { + if let rw @ Some(_) = rewrite_single_line_block( + context, + "do catch ", + block, + Some(&expr.attrs), + None, + shape, + ) { rw } else { // 9 = `do catch ` - let budget = shape.width.checked_sub(9).unwrap_or(0); + let budget = shape.width.saturating_sub(9); Some(format!( "{}{}", "do catch ", rewrite_block( block, Some(&expr.attrs), + None, + context, + Shape::legacy(budget, shape.indent) + )? + )) + } + } + // FIXME(#2743) + ast::ExprKind::ObsoleteInPlace(..) => unimplemented!(), + ast::ExprKind::Async(capture_by, _node_id, ref block) => { + let mover = if capture_by == ast::CaptureBy::Value { + "move " + } else { + "" + }; + if let rw @ Some(_) = rewrite_single_line_block( + context, + format!("{}{}", "async ", mover).as_str(), + block, + Some(&expr.attrs), + None, + shape, + ) { + rw + } else { + // 6 = `async ` + let budget = shape.width.saturating_sub(6); + Some(format!( + "{}{}{}", + "async ", + mover, + rewrite_block( + block, + Some(&expr.attrs), + None, context, Shape::legacy(budget, shape.indent) )? @@ -346,95 +392,6 @@ fn needs_space_after_range(rhs: &ast::Expr) -> bool { }) } -#[derive(new, Clone, Copy)] -pub struct PairParts<'a> { - prefix: &'a str, - infix: &'a str, - suffix: &'a str, -} - -pub fn rewrite_pair( - lhs: &LHS, - rhs: &RHS, - pp: PairParts, - context: &RewriteContext, - shape: Shape, - separator_place: SeparatorPlace, -) -> Option -where - LHS: Rewrite, - RHS: Rewrite, -{ - let lhs_overhead = match separator_place { - SeparatorPlace::Back => shape.used_width() + pp.prefix.len() + pp.infix.trim_right().len(), - SeparatorPlace::Front => shape.used_width(), - }; - let lhs_shape = Shape { - width: context.budget(lhs_overhead), - ..shape - }; - let lhs_result = lhs.rewrite(context, lhs_shape) - .map(|lhs_str| format!("{}{}", pp.prefix, lhs_str))?; - - // Try to put both lhs and rhs on the same line. - let rhs_orig_result = shape - .offset_left(last_line_width(&lhs_result) + pp.infix.len()) - .and_then(|s| s.sub_width(pp.suffix.len())) - .and_then(|rhs_shape| rhs.rewrite(context, rhs_shape)); - if let Some(ref rhs_result) = rhs_orig_result { - // If the length of the lhs is equal to or shorter than the tab width or - // the rhs looks like block expression, we put the rhs on the same - // line with the lhs even if the rhs is multi-lined. - let allow_same_line = lhs_result.len() <= context.config.tab_spaces() - || rhs_result - .lines() - .next() - .map(|first_line| first_line.ends_with('{')) - .unwrap_or(false); - if !rhs_result.contains('\n') || allow_same_line { - let one_line_width = last_line_width(&lhs_result) + pp.infix.len() - + first_line_width(rhs_result) + pp.suffix.len(); - if one_line_width <= shape.width { - return Some(format!( - "{}{}{}{}", - lhs_result, pp.infix, rhs_result, pp.suffix - )); - } - } - } - - // We have to use multiple lines. - // Re-evaluate the rhs because we have more space now: - let mut rhs_shape = match context.config.indent_style() { - IndentStyle::Visual => shape - .sub_width(pp.suffix.len() + pp.prefix.len())? - .visual_indent(pp.prefix.len()), - IndentStyle::Block => { - // Try to calculate the initial constraint on the right hand side. - let rhs_overhead = shape.rhs_overhead(context.config); - Shape::indented(shape.indent.block_indent(context.config), context.config) - .sub_width(rhs_overhead)? - } - }; - let infix = match separator_place { - SeparatorPlace::Back => pp.infix.trim_right(), - SeparatorPlace::Front => pp.infix.trim_left(), - }; - if separator_place == SeparatorPlace::Front { - rhs_shape = rhs_shape.offset_left(infix.len())?; - } - let rhs_result = rhs.rewrite(context, rhs_shape)?; - let indent_str = rhs_shape.indent.to_string_with_newline(context.config); - let infix_with_sep = match separator_place { - SeparatorPlace::Back => format!("{}{}", infix, indent_str), - SeparatorPlace::Front => format!("{}{}", indent_str, infix), - }; - Some(format!( - "{}{}{}{}", - lhs_result, infix_with_sep, rhs_result, pp.suffix - )) -} - pub fn rewrite_array( name: &str, exprs: &[&T], @@ -459,16 +416,18 @@ fn rewrite_empty_block( context: &RewriteContext, block: &ast::Block, attrs: Option<&[ast::Attribute]>, + label: Option, prefix: &str, shape: Shape, ) -> Option { + let label_str = rewrite_label(label); if attrs.map_or(false, |a| !inner_attributes(a).is_empty()) { return None; } if block.stmts.is_empty() && !block_contains_comment(block, context.codemap) && shape.width >= 2 { - return Some(format!("{}{{}}", prefix)); + return Some(format!("{}{}{{}}", prefix, label_str)); } // If a block contains only a single-line comment, then leave it on one line. @@ -476,10 +435,12 @@ fn rewrite_empty_block( let user_str = user_str.trim(); if user_str.starts_with('{') && user_str.ends_with('}') { let comment_str = user_str[1..user_str.len() - 1].trim(); - if block.stmts.is_empty() && !comment_str.contains('\n') && !comment_str.starts_with("//") + if block.stmts.is_empty() + && !comment_str.contains('\n') + && !comment_str.starts_with("//") && comment_str.len() + 4 <= shape.width { - return Some(format!("{}{{ {} }}", prefix, comment_str)); + return Some(format!("{}{}{{ {} }}", prefix, label_str, comment_str)); } } @@ -519,12 +480,14 @@ fn rewrite_single_line_block( prefix: &str, block: &ast::Block, attrs: Option<&[ast::Attribute]>, + label: Option, shape: Shape, ) -> Option { if is_simple_block(block, attrs, context.codemap) { let expr_shape = shape.offset_left(last_line_width(prefix))?; let expr_str = block.stmts[0].rewrite(context, expr_shape)?; - let result = format!("{}{{ {} }}", prefix, expr_str); + let label_str = rewrite_label(label); + let result = format!("{}{}{{ {} }}", prefix, label_str, expr_str); if result.len() <= shape.width && !result.contains('\n') { return Some(result); } @@ -537,10 +500,11 @@ pub fn rewrite_block_with_visitor( prefix: &str, block: &ast::Block, attrs: Option<&[ast::Attribute]>, + label: Option, shape: Shape, has_braces: bool, ) -> Option { - if let rw @ Some(_) = rewrite_empty_block(context, block, attrs, prefix, shape) { + if let rw @ Some(_) = rewrite_empty_block(context, block, attrs, label, prefix, shape) { return rw; } @@ -557,19 +521,21 @@ pub fn rewrite_block_with_visitor( } let inner_attrs = attrs.map(inner_attributes); + let label_str = rewrite_label(label); visitor.visit_block(block, inner_attrs.as_ref().map(|a| &**a), has_braces); - Some(format!("{}{}", prefix, visitor.buffer)) + Some(format!("{}{}{}", prefix, label_str, visitor.buffer)) } impl Rewrite for ast::Block { fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option { - rewrite_block(self, None, context, shape) + rewrite_block(self, None, None, context, shape) } } fn rewrite_block( block: &ast::Block, attrs: Option<&[ast::Attribute]>, + label: Option, context: &RewriteContext, shape: Shape, ) -> Option { @@ -577,14 +543,16 @@ fn rewrite_block( // shape.width is used only for the single line case: either the empty block `{}`, // or an unsafe expression `unsafe { e }`. - if let rw @ Some(_) = rewrite_empty_block(context, block, attrs, &prefix, shape) { + if let rw @ Some(_) = rewrite_empty_block(context, block, attrs, label, &prefix, shape) { return rw; } - let result = rewrite_block_with_visitor(context, &prefix, block, attrs, shape, true); + let result = rewrite_block_with_visitor(context, &prefix, block, attrs, label, shape, true); if let Some(ref result_str) = result { if result_str.lines().count() <= 3 { - if let rw @ Some(_) = rewrite_single_line_block(context, &prefix, block, attrs, shape) { + if let rw @ Some(_) = + rewrite_single_line_block(context, &prefix, block, attrs, label, shape) + { return rw; } } @@ -800,7 +768,7 @@ fn rewrite_single_line( let else_block = self.else_block?; let fixed_cost = self.keyword.len() + " { } else { }".len(); - if let ast::ExprKind::Block(ref else_node) = else_block.node { + if let ast::ExprKind::Block(ref else_node, _) = else_block.node { if !is_simple_block(self.block, None, context.codemap) || !is_simple_block(else_node, None, context.codemap) || pat_expr_str.contains('\n') @@ -915,8 +883,7 @@ fn rewrite_cond( let one_line_budget = context .config .max_width() - .checked_sub(constr_shape.used_width() + offset + brace_overhead) - .unwrap_or(0); + .saturating_sub(constr_shape.used_width() + offset + brace_overhead); let force_newline_brace = (pat_expr_string.contains('\n') || pat_expr_string.len() > one_line_budget) && !last_line_extendable(&pat_expr_string); @@ -926,16 +893,16 @@ fn rewrite_cond( && context .config .width_heuristics() - .single_line_if_else_max_width > 0 + .single_line_if_else_max_width + > 0 { let trial = self.rewrite_single_line(&pat_expr_string, context, shape.width); if let Some(cond_str) = trial { - if cond_str.len() - <= context - .config - .width_heuristics() - .single_line_if_else_max_width + if cond_str.len() <= context + .config + .width_heuristics() + .single_line_if_else_max_width { return Some((cond_str, 0)); } @@ -950,7 +917,8 @@ fn rewrite_cond( // `for event in event` // Do not include label in the span. - let lo = self.label + let lo = self + .label .map_or(self.span.lo(), |label| label.ident.span.hi()); let between_kwd_cond = mk_sp( context @@ -1021,7 +989,7 @@ fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option { return Some(cond_str); } - let block_width = shape.width.checked_sub(used_width).unwrap_or(0); + let block_width = shape.width.saturating_sub(used_width); // This is used only for the empty block case: `{}`. So, we use 1 if we know // we should avoid the single line case. let block_width = if self.else_block.is_some() || self.nested_if { @@ -1036,7 +1004,7 @@ fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option { let block_str = { let old_val = context.is_if_else_block.replace(self.else_block.is_some()); let result = - rewrite_block_with_visitor(context, "", self.block, None, block_shape, true); + rewrite_block_with_visitor(context, "", self.block, None, None, block_shape, true); context.is_if_else_block.replace(old_val); result? }; @@ -1159,8 +1127,10 @@ pub fn is_simple_block( attrs: Option<&[ast::Attribute]>, codemap: &CodeMap, ) -> bool { - (block.stmts.len() == 1 && stmt_is_expr(&block.stmts[0]) - && !block_contains_comment(block, codemap) && attrs.map_or(true, |a| a.is_empty())) + (block.stmts.len() == 1 + && stmt_is_expr(&block.stmts[0]) + && !block_contains_comment(block, codemap) + && attrs.map_or(true, |a| a.is_empty())) } /// Checks whether a block contains at most one statement or expression, and no @@ -1170,7 +1140,8 @@ pub fn is_simple_block_stmt( attrs: Option<&[ast::Attribute]>, codemap: &CodeMap, ) -> bool { - block.stmts.len() <= 1 && !block_contains_comment(block, codemap) + block.stmts.len() <= 1 + && !block_contains_comment(block, codemap) && attrs.map_or(true, |a| a.is_empty()) } @@ -1181,7 +1152,8 @@ pub fn is_empty_block( attrs: Option<&[ast::Attribute]>, codemap: &CodeMap, ) -> bool { - block.stmts.is_empty() && !block_contains_comment(block, codemap) + block.stmts.is_empty() + && !block_contains_comment(block, codemap) && attrs.map_or(true, |a| inner_attributes(a).is_empty()) } @@ -1205,11 +1177,13 @@ pub fn rewrite_multiple_patterns( pats: &[&ast::Pat], shape: Shape, ) -> Option { - let pat_strs = pats.iter() + let pat_strs = pats + .iter() .map(|p| p.rewrite(context, shape)) .collect::>>()?; - let use_mixed_layout = pats.iter() + let use_mixed_layout = pats + .iter() .zip(pat_strs.iter()) .all(|(pat, pat_str)| is_short_pattern(pat, pat_str)); let items: Vec<_> = pat_strs.into_iter().map(ListItem::from_str).collect(); @@ -1231,6 +1205,7 @@ pub fn rewrite_multiple_patterns( shape, ends_with_newline: false, preserve_newline: false, + nested: false, config: context.config, }; write_list(&items, &fmt) @@ -1267,8 +1242,7 @@ fn rewrite_string_lit(context: &RewriteContext, span: Span, shape: Shape) -> Opt new_indent.to_string(context.config), line.trim_left() ) - }) - .collect::>() + }).collect::>() .join("\n") .trim_left(), ); @@ -1284,7 +1258,6 @@ fn rewrite_string_lit(context: &RewriteContext, span: Span, shape: Shape) -> Opt rewrite_string( str_lit, &StringFormat::new(shape.visual_indent(0), context.config), - None, ) } @@ -1376,8 +1349,9 @@ fn is_simple_expr(expr: &ast::Expr) -> bool { | ast::ExprKind::Field(ref expr, _) | ast::ExprKind::Try(ref expr) | ast::ExprKind::Unary(_, ref expr) => is_simple_expr(expr), - ast::ExprKind::Index(ref lhs, ref rhs) | ast::ExprKind::Repeat(ref lhs, ref rhs) => { - is_simple_expr(lhs) && is_simple_expr(rhs) + ast::ExprKind::Index(ref lhs, ref rhs) => is_simple_expr(lhs) && is_simple_expr(rhs), + ast::ExprKind::Repeat(ref lhs, ref rhs) => { + is_simple_expr(lhs) && is_simple_expr(&*rhs.value) } _ => false, } @@ -1468,6 +1442,7 @@ fn rewrite_paren( // Extract comments within parens. let mut pre_comment; let mut post_comment; + let remove_nested_parens = context.config.remove_nested_parens(); loop { // 1 = "(" or ")" let pre_span = mk_sp(span.lo() + BytePos(1), subexpr.span.lo()); @@ -1477,7 +1452,7 @@ fn rewrite_paren( // Remove nested parens if there are no comments. if let ast::ExprKind::Paren(ref subsubexpr) = subexpr.node { - if pre_comment.is_empty() && post_comment.is_empty() { + if remove_nested_parens && pre_comment.is_empty() && post_comment.is_empty() { span = subexpr.span; subexpr = subsubexpr; continue; @@ -1487,27 +1462,15 @@ fn rewrite_paren( break; } - let total_paren_overhead = paren_overhead(context); - let paren_overhead = total_paren_overhead / 2; - let sub_shape = shape - .offset_left(paren_overhead) - .and_then(|s| s.sub_width(paren_overhead))?; - - let paren_wrapper = |s: &str| { - if context.config.spaces_within_parens_and_brackets() && !s.is_empty() { - format!("( {}{}{} )", pre_comment, s, post_comment) - } else { - format!("({}{}{})", pre_comment, s, post_comment) - } - }; + // 1 `(` + let sub_shape = shape.offset_left(1).and_then(|s| s.sub_width(1))?; let subexpr_str = subexpr.rewrite(context, sub_shape)?; debug!("rewrite_paren, subexpr_str: `{:?}`", subexpr_str); - if subexpr_str.contains('\n') - || first_line_width(&subexpr_str) + total_paren_overhead <= shape.width - { - Some(paren_wrapper(&subexpr_str)) + // 2 = `()` + if subexpr_str.contains('\n') || first_line_width(&subexpr_str) + 2 <= shape.width { + Some(format!("({}{}{})", pre_comment, &subexpr_str, post_comment)) } else { None } @@ -1521,54 +1484,44 @@ fn rewrite_index( ) -> Option { let expr_str = expr.rewrite(context, shape)?; - let (lbr, rbr) = if context.config.spaces_within_parens_and_brackets() { - ("[ ", " ]") - } else { - ("[", "]") - }; - - let offset = last_line_width(&expr_str) + lbr.len(); + let offset = last_line_width(&expr_str) + 1; let rhs_overhead = shape.rhs_overhead(context.config); let index_shape = if expr_str.contains('\n') { Shape::legacy(context.config.max_width(), shape.indent) .offset_left(offset) - .and_then(|shape| shape.sub_width(rbr.len() + rhs_overhead)) + .and_then(|shape| shape.sub_width(1 + rhs_overhead)) } else { - shape.visual_indent(offset).sub_width(offset + rbr.len()) + shape.visual_indent(offset).sub_width(offset + 1) }; let orig_index_rw = index_shape.and_then(|s| index.rewrite(context, s)); // Return if index fits in a single line. match orig_index_rw { Some(ref index_str) if !index_str.contains('\n') => { - return Some(format!("{}{}{}{}", expr_str, lbr, index_str, rbr)); + return Some(format!("{}[{}]", expr_str, index_str)); } _ => (), } // Try putting index on the next line and see if it fits in a single line. let indent = shape.indent.block_indent(context.config); - let index_shape = Shape::indented(indent, context.config).offset_left(lbr.len())?; - let index_shape = index_shape.sub_width(rbr.len() + rhs_overhead)?; + let index_shape = Shape::indented(indent, context.config).offset_left(1)?; + let index_shape = index_shape.sub_width(1 + rhs_overhead)?; let new_index_rw = index.rewrite(context, index_shape); match (orig_index_rw, new_index_rw) { (_, Some(ref new_index_str)) if !new_index_str.contains('\n') => Some(format!( - "{}{}{}{}{}", + "{}{}[{}]", expr_str, indent.to_string_with_newline(context.config), - lbr, new_index_str, - rbr )), (None, Some(ref new_index_str)) => Some(format!( - "{}{}{}{}{}", + "{}{}[{}]", expr_str, indent.to_string_with_newline(context.config), - lbr, new_index_str, - rbr )), - (Some(ref index_str), _) => Some(format!("{}{}{}{}", expr_str, lbr, index_str, rbr)), + (Some(ref index_str), _) => Some(format!("{}[{}]", expr_str, index_str)), _ => None, } } @@ -1695,7 +1648,8 @@ pub fn wrap_struct_field( one_line_width: usize, ) -> String { if context.config.indent_style() == IndentStyle::Block - && (fields_str.contains('\n') || !context.config.struct_lit_single_line() + && (fields_str.contains('\n') + || !context.config.struct_lit_single_line() || fields_str.len() > one_line_width) { format!( @@ -1727,12 +1681,12 @@ pub fn rewrite_field( if !attrs_str.is_empty() { attrs_str.push_str(&shape.indent.to_string_with_newline(context.config)); }; - let name = &field.ident.name.to_string(); + let name = context.snippet(field.ident.span); if field.is_shorthand { Some(attrs_str + &name) } else { let mut separator = String::from(struct_lit_field_separator(context.config)); - for _ in 0..prefix_max_width.checked_sub(name.len()).unwrap_or(0) { + for _ in 0..prefix_max_width.saturating_sub(name.len()) { separator.push(' '); } let overhead = name.len() + separator.len(); @@ -1782,13 +1736,7 @@ fn rewrite_tuple_in_visual_indent_style<'a, T>( .next() .unwrap() .rewrite(context, nested_shape) - .map(|s| { - if context.config.spaces_within_parens_and_brackets() { - format!("( {}, )", s) - } else { - format!("({},)", s) - } - }); + .map(|s| format!("({},)", s)); } let list_lo = context.snippet_provider.span_after(span, "("); @@ -1820,15 +1768,12 @@ fn rewrite_tuple_in_visual_indent_style<'a, T>( shape, ends_with_newline: false, preserve_newline: false, + nested: false, config: context.config, }; let list_str = write_list(&item_vec, &fmt)?; - if context.config.spaces_within_parens_and_brackets() && !list_str.is_empty() { - Some(format!("( {} )", list_str)) - } else { - Some(format!("({})", list_str)) - } + Some(format!("({})", list_str)) } pub fn rewrite_tuple<'a, T>( @@ -1934,8 +1879,8 @@ fn rewrite_assignment( pub enum RhsTactics { /// Use heuristics. Default, - /// Put the rhs on the next line if it uses multiple line. - ForceNextLine, + /// Put the rhs on the next line if it uses multiple line, without extra indentation. + ForceNextLineWithoutIndent, } // The left hand side must contain everything up to, and including, the @@ -1957,13 +1902,11 @@ pub fn rewrite_assign_rhs_with, R: Rewrite>( rhs_tactics: RhsTactics, ) -> Option { let lhs = lhs.into(); - let last_line_width = last_line_width(&lhs) - .checked_sub(if lhs.contains('\n') { - shape.indent.width() - } else { - 0 - }) - .unwrap_or(0); + let last_line_width = last_line_width(&lhs).saturating_sub(if lhs.contains('\n') { + shape.indent.width() + } else { + 0 + }); // 1 = space between operator and rhs. let orig_shape = shape.offset_left(last_line_width + 1).unwrap_or(Shape { width: 0, @@ -1994,11 +1937,12 @@ fn choose_rhs( _ => { // Expression did not fit on the same line as the identifier. // Try splitting the line and see if that works better. - let new_shape = - Shape::indented(shape.indent.block_indent(context.config), context.config) - .sub_width(shape.rhs_overhead(context.config))?; + let new_shape = shape_from_rhs_tactic(context, shape, rhs_tactics)?; let new_rhs = expr.rewrite(context, new_shape); - let new_indent_str = &new_shape.indent.to_string_with_newline(context.config); + let new_indent_str = &shape + .indent + .block_indent(context.config) + .to_string_with_newline(context.config); match (orig_rhs, new_rhs) { (Some(ref orig_rhs), Some(ref new_rhs)) @@ -2014,15 +1958,33 @@ fn choose_rhs( } (None, Some(ref new_rhs)) => Some(format!("{}{}", new_indent_str, new_rhs)), (None, None) => None, - (Some(ref orig_rhs), _) => Some(format!(" {}", orig_rhs)), + (Some(orig_rhs), _) => Some(format!(" {}", orig_rhs)), } } } } +fn shape_from_rhs_tactic( + context: &RewriteContext, + shape: Shape, + rhs_tactic: RhsTactics, +) -> Option { + match rhs_tactic { + RhsTactics::ForceNextLineWithoutIndent => Some(shape.with_max_width(context.config)), + RhsTactics::Default => { + Shape::indented(shape.indent.block_indent(context.config), context.config) + .sub_width(shape.rhs_overhead(context.config)) + } + } +} + pub fn prefer_next_line(orig_rhs: &str, next_line_rhs: &str, rhs_tactics: RhsTactics) -> bool { - rhs_tactics == RhsTactics::ForceNextLine || !next_line_rhs.contains('\n') + rhs_tactics == RhsTactics::ForceNextLineWithoutIndent + || !next_line_rhs.contains('\n') || count_newlines(orig_rhs) > count_newlines(next_line_rhs) + 1 + || first_line_ends_with(orig_rhs, '(') && !first_line_ends_with(next_line_rhs, '(') + || first_line_ends_with(orig_rhs, '{') && !first_line_ends_with(next_line_rhs, '{') + || first_line_ends_with(orig_rhs, '[') && !first_line_ends_with(next_line_rhs, '[') } fn rewrite_expr_addrof( @@ -2110,3 +2072,15 @@ fn can_be_overflowed(&self, _: &RewriteContext, _: usize) -> bool { false } } + +pub fn is_method_call(expr: &ast::Expr) -> bool { + match expr.node { + ast::ExprKind::MethodCall(..) => true, + ast::ExprKind::AddrOf(_, ref expr) + | ast::ExprKind::Box(ref expr) + | ast::ExprKind::Cast(ref expr, _) + | ast::ExprKind::Try(ref expr) + | ast::ExprKind::Unary(_, ref expr) => is_method_call(expr), + _ => false, + } +}