use std::cmp::{min, Ordering};
use std::fmt::Write;
-use std::iter::ExactSizeIterator;
+use std::iter::{repeat, ExactSizeIterator};
use syntax::{ast, ptr};
use syntax::codemap::{BytePos, CodeMap, Span};
use {Indent, Shape, Spanned};
use chains::rewrite_chain;
use codemap::{LineRangeUtils, SpanUtils};
-use comment::{contains_comment, recover_comment_removed, rewrite_comment, FindUncommented};
+use comment::{combine_strs_with_missing_comments, contains_comment, recover_comment_removed,
+ rewrite_comment, rewrite_missing_comment, FindUncommented};
use config::{Config, ControlBraceStyle, IndentStyle, MultilineStyle, Style};
use items::{span_hi_for_arg, span_lo_for_arg};
use lists::{definitive_tactic, itemize_list, shape_for_tactic, struct_lit_formatting,
struct_lit_shape, struct_lit_tactic, write_list, DefinitiveListTactic, ListFormatting,
- ListItem, ListTactic, Separator, SeparatorTactic};
-use macros::{rewrite_macro, MacroPosition};
+ ListItem, ListTactic, Separator, SeparatorPlace, SeparatorTactic};
+use macros::{rewrite_macro, MacroArg, MacroPosition};
use patterns::{can_be_overflowed_pat, TuplePatField};
use rewrite::{Rewrite, RewriteContext};
use string::{rewrite_string, StringFormat};
}
}
-#[derive(PartialEq)]
+#[derive(Copy, Clone, PartialEq)]
pub enum ExprType {
Statement,
SubExpression,
}
-fn combine_attr_and_expr(
- context: &RewriteContext,
- shape: Shape,
- expr: &ast::Expr,
- expr_str: &str,
-) -> Option<String> {
- let attrs = outer_attributes(&expr.attrs);
- let attr_str = try_opt!(attrs.rewrite(context, shape));
- let separator = if attr_str.is_empty() {
- String::new()
- } else {
- // Try to recover comments between the attributes and the expression if available.
- let missing_snippet = context.snippet(mk_sp(attrs[attrs.len() - 1].span.hi, expr.span.lo));
- let comment_opening_pos = missing_snippet.chars().position(|c| c == '/');
- let prefer_same_line = if let Some(pos) = comment_opening_pos {
- !missing_snippet[..pos].contains('\n')
- } else {
- !missing_snippet.contains('\n')
- };
-
- let trimmed = missing_snippet.trim();
- let missing_comment = if trimmed.is_empty() {
- String::new()
- } else {
- try_opt!(rewrite_comment(&trimmed, false, shape, context.config))
- };
-
- // 2 = ` ` + ` `
- let one_line_width =
- attr_str.len() + missing_comment.len() + 2 + first_line_width(expr_str);
- let attr_expr_separator = if prefer_same_line && !missing_comment.starts_with("//") &&
- one_line_width <= shape.width
- {
- String::from(" ")
- } else {
- format!("\n{}", shape.indent.to_string(context.config))
- };
-
- if missing_comment.is_empty() {
- attr_expr_separator
- } else {
- // 1 = ` `
- let one_line_width =
- last_line_width(&attr_str) + 1 + first_line_width(&missing_comment);
- let attr_comment_separator = if prefer_same_line && one_line_width <= shape.width {
- String::from(" ")
- } else {
- format!("\n{}", shape.indent.to_string(context.config))
- };
- attr_comment_separator + &missing_comment + &attr_expr_separator
- }
- };
- Some(format!("{}{}{}", attr_str, separator, expr_str))
-}
-
pub fn format_expr(
expr: &ast::Expr,
expr_type: ExprType,
let expr_rw = match expr.node {
ast::ExprKind::Array(ref expr_vec) => rewrite_array(
expr_vec.iter().map(|e| &**e),
- mk_sp(context.codemap.span_after(expr.span, "["), expr.span.hi),
+ mk_sp(context.codemap.span_after(expr.span, "["), expr.span.hi()),
context,
shape,
false,
),
},
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,
ExprType::Statement => {
if is_unsafe_block(block) {
block.rewrite(context, shape)
- } else {
+ } else if let rw @ Some(_) = rewrite_empty_block(context, block, shape) {
// Rewrite block without trying to put it in a single line.
- if let rw @ Some(_) = rewrite_empty_block(context, block, shape) {
- return rw;
- }
+ rw
+ } else {
let prefix = try_opt!(block_prefix(context, block, shape));
rewrite_block_with_visitor(context, &prefix, block, shape)
}
)
}
}
+ ast::ExprKind::Yield(ref opt_expr) => if let Some(ref expr) = *opt_expr {
+ rewrite_unary_prefix(context, "yield ", &**expr, shape)
+ } else {
+ wrap_str("yield".to_string(), context.config.max_width(), shape)
+ },
ast::ExprKind::Closure(capture, ref fn_decl, ref body, _) => {
rewrite_closure(capture, fn_decl, body, expr.span, context, shape)
}
}
match (lhs.as_ref().map(|x| &**x), rhs.as_ref().map(|x| &**x)) {
- (Some(ref lhs), Some(ref rhs)) => {
+ (Some(lhs), Some(rhs)) => {
let sp_delim = if context.config.spaces_around_ranges() {
format!(" {} ", delim)
} else if needs_space_before_range(context, lhs) {
} else {
delim.into()
};
- rewrite_pair(&**lhs, &**rhs, "", &sp_delim, "", context, shape)
+ rewrite_pair(&*lhs, &*rhs, "", &sp_delim, "", context, shape)
}
- (None, Some(ref rhs)) => {
+ (None, Some(rhs)) => {
let sp_delim = if context.config.spaces_around_ranges() {
format!("{} ", delim)
} else {
delim.into()
};
- rewrite_unary_prefix(context, &sp_delim, &**rhs, shape)
+ rewrite_unary_prefix(context, &sp_delim, &*rhs, shape)
}
- (Some(ref lhs), None) => {
+ (Some(lhs), None) => {
let sp_delim = if context.config.spaces_around_ranges() {
format!(" {}", delim)
} else {
delim.into()
};
- rewrite_unary_suffix(context, &sp_delim, &**lhs, shape)
+ rewrite_unary_suffix(context, &sp_delim, &*lhs, shape)
}
(None, None) => wrap_str(delim.into(), context.config.max_width(), shape),
}
shape,
),
ast::ExprKind::Catch(ref block) => {
- if let rewrite @ Some(_) = rewrite_single_line_block(context, "do catch ", block, shape)
- {
- return rewrite;
+ if let rw @ Some(_) = rewrite_single_line_block(context, "do catch ", block, shape) {
+ rw
+ } else {
+ // 9 = `do catch `
+ let budget = shape.width.checked_sub(9).unwrap_or(0);
+ Some(format!(
+ "{}{}",
+ "do catch ",
+ try_opt!(block.rewrite(&context, Shape::legacy(budget, shape.indent)))
+ ))
}
- // 9 = `do catch `
- let budget = shape.width.checked_sub(9).unwrap_or(0);
- Some(format!(
- "{}{}",
- "do catch ",
- try_opt!(block.rewrite(&context, Shape::legacy(budget, shape.indent)))
- ))
}
};
recover_comment_removed(expr_str, expr.span, context, shape)
})
.and_then(|expr_str| {
- combine_attr_and_expr(context, shape, expr, &expr_str)
+ let attrs = outer_attributes(&expr.attrs);
+ let attrs_str = try_opt!(attrs.rewrite(context, shape));
+ let span = mk_sp(
+ attrs.last().map_or(expr.span.lo(), |attr| attr.span.hi()),
+ expr.span.lo(),
+ );
+ combine_strs_with_missing_comments(context, &attrs_str, &expr_str, span, shape, false)
})
}
1 // "["
};
- let mut nested_shape = match context.config.array_layout() {
+ let nested_shape = match context.config.array_layout() {
IndentStyle::Block => try_opt!(
shape
.block()
context.codemap,
expr_iter,
"]",
- |item| item.span.lo,
- |item| item.span.hi,
+ |item| item.span.lo(),
+ |item| item.span.hi(),
|item| item.rewrite(context, nested_shape),
- span.lo,
- span.hi,
+ span.lo(),
+ span.hi(),
+ false,
).collect::<Vec<_>>();
if items.is_empty() {
DefinitiveListTactic::Mixed
},
};
- let mut ends_with_newline = tactic.ends_with_newline(context.config.array_layout());
+ let ends_with_newline = tactic.ends_with_newline(context.config.array_layout());
if context.config.array_horizontal_layout_threshold() > 0 &&
items.len() > context.config.array_horizontal_layout_threshold()
{
tactic = DefinitiveListTactic::Mixed;
- ends_with_newline = false;
- if context.config.array_layout() == IndentStyle::Block {
- nested_shape = try_opt!(
- shape
- .visual_indent(bracket_size)
- .sub_width(bracket_size * 2)
- );
- }
}
let fmt = ListFormatting {
} else {
SeparatorTactic::Vertical
},
+ separator_place: SeparatorPlace::Back,
shape: nested_shape,
ends_with_newline: ends_with_newline,
preserve_newline: false,
let list_str = try_opt!(write_list(&items, &fmt));
let result = if context.config.array_layout() == IndentStyle::Visual ||
- tactic != DefinitiveListTactic::Vertical
+ tactic == DefinitiveListTactic::Horizontal
{
- if context.config.spaces_within_square_brackets() && list_str.len() > 0 {
+ if context.config.spaces_within_square_brackets() && !list_str.is_empty() {
format!("[ {} ]", list_str)
} else {
format!("[{}]", list_str)
|arg| span_hi_for_arg(context, arg),
|arg| arg.rewrite(context, arg_shape),
context.codemap.span_after(span, "|"),
- body.span.lo,
+ body.span.lo(),
+ false,
);
let item_vec = arg_items.collect::<Vec<_>>();
// 1 = space between arguments and return type.
tactic: tactic,
separator: ",",
trailing_separator: SeparatorTactic::Never,
+ separator_place: SeparatorPlace::Back,
shape: arg_shape,
ends_with_newline: false,
preserve_newline: true,
};
if no_return_type && !needs_block {
// lock.stmts.len() == 1
- if let Some(ref expr) = stmt_expr(&block.stmts[0]) {
+ if let Some(expr) = stmt_expr(&block.stmts[0]) {
if let Some(rw) = rewrite_closure_expr(expr, &prefix, context, body_shape) {
return Some(rw);
}
}
// Either we require a block, or tried without and failed.
- rewrite_closure_block(&block, &prefix, context, body_shape)
+ rewrite_closure_block(block, &prefix, context, body_shape)
} else {
rewrite_closure_expr(body, &prefix, context, body_shape).or_else(|| {
// The closure originally had a non-block expression, but we can't fit on
if classify::expr_requires_semi_to_be_stmt(left_most_sub_expr(expr)) {
rewrite = and_one_line(rewrite);
}
+ rewrite = rewrite.and_then(|rw| {
+ if context.config.multiline_closure_forces_block() && rw.contains('\n') {
+ None
+ } else {
+ Some(rw)
+ }
+ });
rewrite.map(|rw| format!("{} {}", prefix, rw))
}
// closure is large.
let block_threshold = context.config.closure_block_indent_threshold();
if block_threshold >= 0 {
- if let Some(block_str) = block.rewrite(&context, shape) {
+ if let Some(block_str) = block.rewrite(context, shape) {
if block_str.matches('\n').count() <= block_threshold as usize &&
!need_block_indent(&block_str, shape)
{
// The body of the closure is big enough to be block indented, that
// means we must re-format.
let block_shape = shape.block();
- let block_str = try_opt!(block.rewrite(&context, block_shape));
+ let block_str = try_opt!(block.rewrite(context, block_shape));
Some(format!("{} {}", prefix, block_str))
}
ast::BlockCheckMode::Unsafe(..) => {
let snippet = context.snippet(block.span);
let open_pos = try_opt!(snippet.find_uncommented("{"));
- visitor.last_pos = block.span.lo + BytePos(open_pos as u32)
+ visitor.last_pos = block.span.lo() + BytePos(open_pos as u32)
}
- ast::BlockCheckMode::Default => visitor.last_pos = block.span.lo,
+ ast::BlockCheckMode::Default => visitor.last_pos = block.span.lo(),
}
visitor.visit_block(block, None);
""
};
- format_expr(
- ex,
- match self.node {
- ast::StmtKind::Expr(_) => ExprType::SubExpression,
- ast::StmtKind::Semi(_) => ExprType::Statement,
- _ => unreachable!(),
- },
- context,
- try_opt!(shape.sub_width(suffix.len())),
- ).map(|s| s + suffix)
+ let shape = try_opt!(shape.sub_width(suffix.len()));
+ format_expr(ex, ExprType::Statement, context, shape).map(|s| s + suffix)
}
ast::StmtKind::Mac(..) | ast::StmtKind::Item(..) => None,
};
let new_width = try_opt!(width.checked_sub(pat_expr_str.len() + fixed_cost));
let expr = &self.block.stmts[0];
- let if_str = try_opt!(expr.rewrite(
- context,
- Shape::legacy(new_width, Indent::empty()),
- ));
+ let if_str = try_opt!(expr.rewrite(context, Shape::legacy(new_width, Indent::empty())));
let new_width = try_opt!(new_width.checked_sub(if_str.len()));
let else_expr = &else_node.stmts[0];
let cond_span = if let Some(cond) = self.cond {
cond.span
} else {
- mk_sp(self.block.span.lo, self.block.span.lo)
+ mk_sp(self.block.span.lo(), self.block.span.lo())
};
- // for event in event
+ // `for event in event`
+ // Do not include label in the span.
+ let lo = self.label.map_or(self.span.lo(), |label| label.span.hi());
let between_kwd_cond = mk_sp(
- context.codemap.span_after(self.span, self.keyword.trim()),
- self.pat.map_or(
- cond_span.lo,
- |p| if self.matcher.is_empty() {
- p.span.lo
+ context
+ .codemap
+ .span_after(mk_sp(lo, self.span.hi()), self.keyword.trim()),
+ self.pat
+ .map_or(cond_span.lo(), |p| if self.matcher.is_empty() {
+ p.span.lo()
} else {
context.codemap.span_before(self.span, self.matcher.trim())
- },
- ),
+ }),
);
let between_kwd_cond_comment = extract_comment(between_kwd_cond, context, shape);
let after_cond_comment =
- extract_comment(mk_sp(cond_span.hi, self.block.span.lo), context, shape);
+ extract_comment(mk_sp(cond_span.hi(), self.block.span.lo()), context, shape);
let block_sep = if self.cond.is_none() && between_kwd_cond_comment.is_some() {
""
next_else_block.as_ref().map(|e| &**e),
false,
true,
- mk_sp(else_block.span.lo, self.span.hi),
+ mk_sp(else_block.span.lo(), self.span.hi()),
).rewrite(context, shape)
}
ast::ExprKind::If(ref cond, ref if_block, ref next_else_block) => {
next_else_block.as_ref().map(|e| &**e),
false,
true,
- mk_sp(else_block.span.lo, self.span.hi),
+ mk_sp(else_block.span.lo(), self.span.hi()),
).rewrite(context, shape)
}
_ => {
};
let between_kwd_else_block = mk_sp(
- self.block.span.hi,
+ self.block.span.hi(),
context
.codemap
- .span_before(mk_sp(self.block.span.hi, else_block.span.lo), "else"),
+ .span_before(mk_sp(self.block.span.hi(), else_block.span.lo()), "else"),
);
let between_kwd_else_block_comment =
extract_comment(between_kwd_else_block, context, shape);
let after_else = mk_sp(
context
.codemap
- .span_after(mk_sp(self.block.span.hi, else_block.span.lo), "else"),
- else_block.span.lo,
+ .span_after(mk_sp(self.block.span.hi(), else_block.span.lo()), "else"),
+ else_block.span.lo(),
);
let after_else_comment = extract_comment(after_else, context, shape);
}
fn extract_comment(span: Span, context: &RewriteContext, shape: Shape) -> Option<String> {
- let comment_str = context.snippet(span);
- if contains_comment(&comment_str) {
- let comment = try_opt!(rewrite_comment(
- comment_str.trim(),
- false,
- shape,
- context.config,
- ));
- Some(format!(
+ match rewrite_missing_comment(span, shape, context) {
+ Some(ref comment) if !comment.is_empty() => Some(format!(
"\n{indent}{}\n{indent}",
comment,
indent = shape.indent.to_string(context.config)
- ))
- } else {
- None
+ )),
+ _ => None,
}
}
}
}
-// inter-match-arm-comment-rules:
-// - all comments following a match arm before the start of the next arm
-// are about the second arm
-fn rewrite_match_arm_comment(
- context: &RewriteContext,
- missed_str: &str,
- shape: Shape,
- arm_indent_str: &str,
-) -> Option<String> {
- // The leading "," is not part of the arm-comment
- let missed_str = match missed_str.find_uncommented(",") {
- Some(n) => &missed_str[n + 1..],
- None => &missed_str[..],
- };
-
- let mut result = String::new();
- // any text not preceeded by a newline is pushed unmodified to the block
- let first_brk = missed_str.find(|c: char| c == '\n').unwrap_or(0);
- result.push_str(&missed_str[..first_brk]);
- let missed_str = &missed_str[first_brk..]; // If missed_str had one newline, it starts with it
+// A simple wrapper type against ast::Arm. Used inside write_list().
+struct ArmWrapper<'a> {
+ pub arm: &'a ast::Arm,
+ // True if the arm is the last one in match expression. Used to decide on whether we should add
+ // trailing comma to the match arm when `config.trailing_comma() == Never`.
+ pub is_last: bool,
+}
- let first = missed_str
- .find(|c: char| !c.is_whitespace())
- .unwrap_or(missed_str.len());
- if missed_str[..first].chars().filter(|c| c == &'\n').count() >= 2 {
- // Excessive vertical whitespace before comment should be preserved
- // FIXME handle vertical whitespace better
- result.push('\n');
- }
- let missed_str = missed_str[first..].trim();
- if !missed_str.is_empty() {
- let comment = try_opt!(rewrite_comment(&missed_str, false, shape, context.config));
- result.push('\n');
- result.push_str(arm_indent_str);
- result.push_str(&comment);
+impl<'a> ArmWrapper<'a> {
+ pub fn new(arm: &'a ast::Arm, is_last: bool) -> ArmWrapper<'a> {
+ ArmWrapper { arm, is_last }
}
+}
- Some(result)
+impl<'a> Rewrite for ArmWrapper<'a> {
+ fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
+ rewrite_match_arm(context, self.arm, shape, self.is_last)
+ }
}
fn rewrite_match(
try_opt!(
inner_attrs
.rewrite(context, shape)
- .map(|s| format!("\n{}{}", nested_indent_str, s))
+ .map(|s| format!("{}{}\n", nested_indent_str, s))
)
};
let open_brace_pos = if inner_attrs.is_empty() {
context
.codemap
- .span_after(mk_sp(cond.span.hi, arms[0].span().lo), "{")
+ .span_after(mk_sp(cond.span.hi(), arms[0].span().lo()), "{")
+ } else {
+ inner_attrs[inner_attrs.len() - 1].span().hi()
+ };
+
+ let arm_indent_str = if context.config.indent_match_arms() {
+ nested_indent_str
} else {
- inner_attrs[inner_attrs.len() - 1].span().hi
+ shape.indent.to_string(context.config)
};
Some(format!(
- "match {}{}{{{}{}\n{}}}",
+ "match {}{}{{\n{}{}{}\n{}}}",
cond_str,
block_sep,
inner_attrs_str,
+ arm_indent_str,
try_opt!(rewrite_match_arms(
context,
arms,
))
}
-fn arm_comma(config: &Config, body: &ast::Expr) -> &'static str {
- if config.match_block_trailing_comma() {
+fn arm_comma(config: &Config, body: &ast::Expr, is_last: bool) -> &'static str {
+ if is_last && config.trailing_comma() == SeparatorTactic::Never {
+ ""
+ } else if config.match_block_trailing_comma() {
","
} else if let ast::ExprKind::Block(ref block) = body.node {
if let ast::BlockCheckMode::Default = block.rules {
span: Span,
open_brace_pos: BytePos,
) -> Option<String> {
- let mut result = String::new();
-
let arm_shape = if context.config.indent_match_arms() {
shape.block_indent(context.config.tab_spaces())
} else {
shape.block_indent(0)
}.with_max_width(context.config);
- let arm_indent_str = arm_shape.indent.to_string(context.config);
- let arm_num = arms.len();
- for (i, arm) in arms.iter().enumerate() {
- // Make sure we get the stuff between arms.
- let missed_str = if i == 0 {
- context.snippet(mk_sp(open_brace_pos, arm.span().lo))
- } else {
- context.snippet(mk_sp(arms[i - 1].span().hi, arm.span().lo))
- };
- let comment = try_opt!(rewrite_match_arm_comment(
- context,
- &missed_str,
- arm_shape,
- &arm_indent_str,
- ));
- if !comment.chars().all(|c| c == ' ') {
- result.push_str(&comment);
- }
- result.push('\n');
- result.push_str(&arm_indent_str);
-
- let arm_str = rewrite_match_arm(context, arm, arm_shape);
- if let Some(ref arm_str) = arm_str {
- // Trim the trailing comma if necessary.
- if i == arm_num - 1 && context.config.trailing_comma() == SeparatorTactic::Never &&
- arm_str.ends_with(',')
- {
- result.push_str(&arm_str[0..arm_str.len() - 1])
- } else {
- result.push_str(arm_str)
- }
- } else {
- // We couldn't format the arm, just reproduce the source.
- let snippet = context.snippet(arm.span());
- result.push_str(&snippet);
- if context.config.trailing_comma() != SeparatorTactic::Never {
- result.push_str(arm_comma(context.config, &arm.body))
- }
- }
- }
- // BytePos(1) = closing match brace.
- let last_span = mk_sp(arms[arms.len() - 1].span().hi, span.hi - BytePos(1));
- let last_comment = context.snippet(last_span);
- let comment = try_opt!(rewrite_match_arm_comment(
- context,
- &last_comment,
- arm_shape,
- &arm_indent_str,
- ));
- result.push_str(&comment);
+ let arm_len = arms.len();
+ let is_last_iter = repeat(false)
+ .take(arm_len.checked_sub(1).unwrap_or(0))
+ .chain(repeat(true));
+ let items = itemize_list(
+ context.codemap,
+ arms.iter()
+ .zip(is_last_iter)
+ .map(|(arm, is_last)| ArmWrapper::new(arm, is_last)),
+ "}",
+ |arm| arm.arm.span().lo(),
+ |arm| arm.arm.span().hi(),
+ |arm| arm.rewrite(context, arm_shape),
+ open_brace_pos,
+ span.hi(),
+ false,
+ );
+ let arms_vec: Vec<_> = items.collect();
+ let fmt = ListFormatting {
+ tactic: DefinitiveListTactic::Vertical,
+ // We will add/remove commas inside `arm.rewrite()`, and hence no separator here.
+ separator: "",
+ trailing_separator: SeparatorTactic::Never,
+ separator_place: SeparatorPlace::Back,
+ shape: arm_shape,
+ ends_with_newline: true,
+ preserve_newline: true,
+ config: context.config,
+ };
- Some(result)
+ write_list(&arms_vec, &fmt)
}
-fn rewrite_match_arm(context: &RewriteContext, arm: &ast::Arm, shape: Shape) -> Option<String> {
- let attr_str = if !arm.attrs.is_empty() {
+fn rewrite_match_arm(
+ context: &RewriteContext,
+ arm: &ast::Arm,
+ shape: Shape,
+ is_last: bool,
+) -> Option<String> {
+ let (missing_span, attrs_str) = if !arm.attrs.is_empty() {
if contains_skip(&arm.attrs) {
- return None;
+ let (_, body) = flatten_arm_body(context, &arm.body);
+ // `arm.span()` does not include trailing comma, add it manually.
+ return Some(format!(
+ "{}{}",
+ context.snippet(arm.span()),
+ arm_comma(context.config, body, is_last),
+ ));
}
- format!(
- "{}\n{}",
+ (
+ mk_sp(
+ arm.attrs[arm.attrs.len() - 1].span.hi(),
+ arm.pats[0].span.lo(),
+ ),
try_opt!(arm.attrs.rewrite(context, shape)),
- shape.indent.to_string(context.config)
)
} else {
- String::new()
+ (mk_sp(arm.span().lo(), arm.span().lo()), String::new())
};
- let pats_str = try_opt!(rewrite_match_pattern(context, &arm.pats, &arm.guard, shape));
- let pats_str = attr_str + &pats_str;
- rewrite_match_body(context, &arm.body, &pats_str, shape, arm.guard.is_some())
+ let pats_str = try_opt!(
+ rewrite_match_pattern(context, &arm.pats, &arm.guard, shape).and_then(|pats_str| {
+ combine_strs_with_missing_comments(
+ context,
+ &attrs_str,
+ &pats_str,
+ missing_span,
+ shape,
+ false,
+ )
+ })
+ );
+ rewrite_match_body(
+ context,
+ &arm.body,
+ &pats_str,
+ shape,
+ arm.guard.is_some(),
+ is_last,
+ )
}
fn rewrite_match_pattern(
context: &RewriteContext,
- pats: &Vec<ptr::P<ast::Pat>>,
+ pats: &[ptr::P<ast::Pat>],
guard: &Option<ptr::P<ast::Expr>>,
shape: Shape,
) -> Option<String> {
tactic: tactic,
separator: " |",
trailing_separator: SeparatorTactic::Never,
+ separator_place: context.config.match_pattern_separator_break_point(),
shape: pat_shape,
ends_with_newline: false,
preserve_newline: false,
Some(format!("{}{}", pats_str, guard_str))
}
-fn rewrite_match_body(
- context: &RewriteContext,
- body: &ptr::P<ast::Expr>,
- pats_str: &str,
- shape: Shape,
- has_guard: bool,
-) -> Option<String> {
- let (extend, body) = match body.node {
+// (extend, body)
+// @extend: true if the arm body can be put next to `=>`
+// @body: flattened body, if the body is block with a single expression
+fn flatten_arm_body<'a>(context: &'a RewriteContext, body: &'a ast::Expr) -> (bool, &'a ast::Expr) {
+ match body.node {
ast::ExprKind::Block(ref block)
if !is_unsafe_block(block) && is_simple_block(block, context.codemap) =>
{
if let ast::StmtKind::Expr(ref expr) = block.stmts[0].node {
- (expr.can_be_overflowed(context, 1), &**expr)
+ (
+ !context.config.multiline_match_arm_forces_block() &&
+ expr.can_be_overflowed(context, 1),
+ &**expr,
+ )
} else {
- (false, &**body)
+ (false, &*body)
}
}
- _ => (body.can_be_overflowed(context, 1), &**body),
- };
+ _ => (
+ !context.config.multiline_match_arm_forces_block() &&
+ body.can_be_overflowed(context, 1),
+ &*body,
+ ),
+ }
+}
+
+fn rewrite_match_body(
+ context: &RewriteContext,
+ body: &ptr::P<ast::Expr>,
+ pats_str: &str,
+ shape: Shape,
+ has_guard: bool,
+ is_last: bool,
+) -> Option<String> {
+ let (extend, body) = flatten_arm_body(context, body);
- let comma = arm_comma(&context.config, body);
+ let comma = arm_comma(context.config, body, is_last);
let alt_block_sep = String::from("\n") + &shape.indent.block_only().to_string(context.config);
let alt_block_sep = alt_block_sep.as_str();
let (is_block, is_empty_block) = if let ast::ExprKind::Block(ref block) = body.node {
// Let's try and get the arm body on the same line as the condition.
// 4 = ` => `.len()
let orig_body_shape = shape
- .offset_left(extra_offset(&pats_str, shape) + 4)
+ .offset_left(extra_offset(pats_str, shape) + 4)
.and_then(|shape| shape.sub_width(comma.len()));
let orig_body = if let Some(body_shape) = orig_body_shape {
let rewrite = nop_block_collapse(
string: &str,
shape: Shape,
) -> bool {
- if context.codemap.lookup_char_pos(span.lo).col.0 != shape.indent.width() {
+ if context.codemap.lookup_char_pos(span.lo()).col.0 != shape.indent.width() {
return true;
}
if line.len() > shape.width {
return true;
}
- } else {
- if line.len() > shape.width + shape.indent.width() {
- return true;
- }
+ } else if line.len() > shape.width + shape.indent.width() {
+ return true;
}
}
};
rewrite_call_inner(
context,
- &callee,
+ callee,
&args.iter().map(|x| &**x).collect::<Vec<_>>(),
span,
shape,
} else {
1
};
- let used_width = extra_offset(&callee_str, shape);
+ let used_width = extra_offset(callee_str, shape);
let one_line_width = shape
.width
.checked_sub(used_width + 2 * paren_overhead)
).ok_or(Ordering::Greater)?;
let span_lo = context.codemap.span_after(span, "(");
- let args_span = mk_sp(span_lo, span.hi);
+ let args_span = mk_sp(span_lo, span.hi());
let (extendable, list_str) = rewrite_call_args(
context,
}
let args_shape = shape
- .sub_width(last_line_width(&callee_str))
+ .sub_width(last_line_width(callee_str))
.ok_or(Ordering::Less)?;
Ok(format!(
"{}{}",
context.codemap,
args.iter(),
")",
- |item| item.span().lo,
- |item| item.span().hi,
+ |item| item.span().lo(),
+ |item| item.span().hi(),
|item| item.rewrite(context, shape),
- span.lo,
- span.hi,
+ span.lo(),
+ span.hi(),
+ true,
);
let mut item_vec: Vec<_> = items.collect();
} else {
context.config.trailing_comma()
},
+ separator_place: SeparatorPlace::Back,
shape: shape,
ends_with_newline: context.use_block_indent() && tactic == DefinitiveListTactic::Vertical,
preserve_newline: false,
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
// first arguments.
- let (orig_last, placeholder) = if overflow_last {
+ let placeholder = if overflow_last {
let mut context = context.clone();
if let Some(expr) = args[args.len() - 1].to_expr() {
- match expr.node {
- ast::ExprKind::MethodCall(..) => context.force_one_line_chain = true,
- _ => (),
+ if let ast::ExprKind::MethodCall(..) = expr.node {
+ context.force_one_line_chain = true;
}
}
- last_arg_shape(&context, &item_vec, shape, args_max_width)
- .map_or((None, None), |arg_shape| {
- rewrite_last_arg_with_overflow(
- &context,
- args,
- &mut item_vec[args.len() - 1],
- arg_shape,
- )
- })
+ last_arg_shape(&context, item_vec, shape, args_max_width).and_then(|arg_shape| {
+ rewrite_last_arg_with_overflow(&context, args, &mut item_vec[args.len() - 1], arg_shape)
+ })
} else {
- (None, None)
+ None
};
- let tactic = definitive_tactic(
+ let mut tactic = definitive_tactic(
&*item_vec,
ListTactic::LimitedHorizontalVertical(args_max_width),
Separator::Comma,
(true, DefinitiveListTactic::Horizontal, placeholder @ Some(..)) => {
item_vec[args.len() - 1].item = placeholder;
}
- (true, _, _) => {
- item_vec[args.len() - 1].item = orig_last;
+ _ if args.len() >= 1 => {
+ item_vec[args.len() - 1].item = args.last()
+ .and_then(|last_arg| last_arg.rewrite(context, shape));
+ tactic = definitive_tactic(
+ &*item_vec,
+ ListTactic::LimitedHorizontalVertical(args_max_width),
+ Separator::Comma,
+ one_line_width,
+ );
}
- (false, _, _) => {}
+ _ => (),
}
tactic
fn last_arg_shape(
context: &RewriteContext,
- items: &Vec<ListItem>,
+ items: &[ListItem],
shape: Shape,
args_max_width: usize,
) -> Option<Shape> {
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(args_max_width, shape.width);
let arg_indent = if context.use_block_indent() {
args: &[&T],
last_item: &mut ListItem,
shape: Shape,
-) -> (Option<String>, Option<String>)
+) -> Option<String>
where
T: Rewrite + Spanned + ToExpr + 'a,
{
} else {
last_arg.rewrite(context, shape)
};
- let orig_last = last_item.item.clone();
if let Some(rewrite) = rewrite {
let rewrite_first_line = Some(rewrite[..first_line_width(&rewrite)].to_owned());
last_item.item = rewrite_first_line;
- (orig_last, Some(rewrite))
+ Some(rewrite)
} else {
- (orig_last, None)
+ None
}
}
(context.inside_macro && !args_str.contains('\n') &&
args_str.len() + paren_overhead(context) <= shape.width) || is_extendable
{
- if context.config.spaces_within_parens() && args_str.len() > 0 {
+ if context.config.spaces_within_parens() && !args_str.is_empty() {
format!("( {} )", args_str)
} else {
format!("({})", args_str)
.and_then(|s| s.sub_width(paren_overhead))
);
- let paren_wrapper = |s: &str| if context.config.spaces_within_parens() && s.len() > 0 {
+ let paren_wrapper = |s: &str| if context.config.spaces_within_parens() && !s.is_empty() {
format!("( {} )", s)
} else {
format!("({})", s)
(_, Some(ref new_index_str)) if !new_index_str.contains('\n') => Some(format!(
"{}\n{}{}{}{}",
expr_str,
- indent.to_string(&context.config),
+ indent.to_string(context.config),
lbr,
new_index_str,
rbr
(None, Some(ref new_index_str)) => Some(format!(
"{}\n{}{}{}{}",
expr_str,
- indent.to_string(&context.config),
+ indent.to_string(context.config),
lbr,
new_index_str,
rbr
path_shape,
));
- if fields.len() == 0 && base.is_none() {
+ if fields.is_empty() && base.is_none() {
return Some(format!("{} {{}}", path_str));
}
fields,
context,
shape,
- mk_sp(body_lo, span.hi),
+ mk_sp(body_lo, span.hi()),
one_line_width,
))
} else {
.chain(base.into_iter().map(StructLitField::Base));
let span_lo = |item: &StructLitField| match *item {
- StructLitField::Regular(field) => field.span().lo,
+ StructLitField::Regular(field) => field.span().lo(),
StructLitField::Base(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)
}
};
let span_hi = |item: &StructLitField| match *item {
- StructLitField::Regular(field) => field.span().hi,
- StructLitField::Base(expr) => expr.span.hi,
+ StructLitField::Regular(field) => field.span().hi(),
+ StructLitField::Base(expr) => expr.span.hi(),
};
let rewrite = |item: &StructLitField| match *item {
StructLitField::Regular(field) => {
span_hi,
rewrite,
body_lo,
- span.hi,
+ span.hi(),
+ false,
);
let item_vec = items.collect::<Vec<_>>();
"{}{}:\n{}{}",
attrs_str,
name,
- expr_offset.to_string(&context.config),
+ expr_offset.to_string(context.config),
s
)
})
context.codemap,
items,
")",
- |item| item.span().lo,
- |item| item.span().hi,
+ |item| item.span().lo(),
+ |item| item.span().hi(),
|item| item.rewrite(context, nested_shape),
list_lo,
- span.hi - BytePos(1),
+ span.hi() - BytePos(1),
+ false,
);
let item_vec: Vec<_> = items.collect();
let tactic = definitive_tactic(
tactic: tactic,
separator: ",",
trailing_separator: SeparatorTactic::Never,
+ separator_place: SeparatorPlace::Back,
shape: shape,
ends_with_newline: false,
preserve_newline: false,
};
let list_str = try_opt!(write_list(&item_vec, &fmt));
- if context.config.spaces_within_parens() && list_str.len() > 0 {
+ if context.config.spaces_within_parens() && !list_str.is_empty() {
Some(format!("( {} )", list_str))
} else {
Some(format!("({})", list_str))
{
debug!("rewrite_tuple {:?}", shape);
if context.use_block_indent() {
- // We use the same rule as funcation call for rewriting tuple.
+ // We use the same rule as function calls for rewriting tuples.
let force_trailing_comma = if context.inside_macro {
span_ends_with_comma(context, span)
} else {
}
fn prefer_next_line(orig_rhs: &str, next_line_rhs: &str) -> bool {
-
fn count_line_breaks(src: &str) -> usize {
src.chars().filter(|&x| x == '\n').count()
}
false
}
}
+
+impl<'a> ToExpr for MacroArg {
+ fn to_expr(&self) -> Option<&ast::Expr> {
+ match self {
+ &MacroArg::Expr(ref expr) => Some(expr),
+ _ => None,
+ }
+ }
+
+ fn can_be_overflowed(&self, context: &RewriteContext, len: usize) -> bool {
+ match self {
+ &MacroArg::Expr(ref expr) => can_be_overflowed_expr(context, expr, len),
+ &MacroArg::Ty(ref ty) => can_be_overflowed_type(context, ty, len),
+ &MacroArg::Pat(..) => false,
+ }
+ }
+}