2015-04-21 21:01:19 +12:00
|
|
|
// 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.
|
|
|
|
|
2017-09-15 18:11:24 +09:00
|
|
|
use std::borrow::Cow;
|
2017-12-24 00:28:58 +09:00
|
|
|
use std::cmp::min;
|
2017-07-13 18:42:14 +09:00
|
|
|
|
2018-02-07 22:48:05 +09:00
|
|
|
use config::lists::*;
|
2018-03-26 07:36:44 +09:00
|
|
|
use syntax::parse::token::DelimToken;
|
2018-08-23 17:14:19 -04:00
|
|
|
use syntax::source_map::{BytePos, SourceMap, Span};
|
2018-03-14 20:43:01 +13:00
|
|
|
use syntax::{ast, ptr};
|
2015-09-04 18:09:05 +02:00
|
|
|
|
2015-09-11 00:52:16 +02:00
|
|
|
use chains::rewrite_chain;
|
2017-11-13 15:26:33 +13:00
|
|
|
use closures;
|
2018-04-29 20:22:48 +08:00
|
|
|
use comment::{
|
|
|
|
combine_strs_with_missing_comments, contains_comment, recover_comment_removed, rewrite_comment,
|
|
|
|
rewrite_missing_comment, CharClasses, FindUncommented,
|
|
|
|
};
|
2017-11-24 14:45:18 +13:00
|
|
|
use config::{Config, ControlBraceStyle, IndentStyle};
|
2018-04-29 20:22:48 +08:00
|
|
|
use lists::{
|
|
|
|
definitive_tactic, itemize_list, shape_for_tactic, struct_lit_formatting, struct_lit_shape,
|
|
|
|
struct_lit_tactic, write_list, ListFormatting, ListItem, Separator,
|
|
|
|
};
|
2017-08-30 12:00:10 +09:00
|
|
|
use macros::{rewrite_macro, MacroArg, MacroPosition};
|
2018-03-21 22:02:18 +09:00
|
|
|
use matches::rewrite_match;
|
2018-03-07 15:40:52 +09:00
|
|
|
use overflow;
|
2018-06-30 19:53:06 +12:00
|
|
|
use pairs::{rewrite_all_pairs, rewrite_pair, PairParts};
|
2018-03-21 22:02:18 +09:00
|
|
|
use patterns::{can_be_overflowed_pat, is_short_pattern, TuplePatField};
|
2017-07-13 18:42:14 +09:00
|
|
|
use rewrite::{Rewrite, RewriteContext};
|
2017-09-17 15:23:25 +09:00
|
|
|
use shape::{Indent, Shape};
|
2018-08-23 17:14:19 -04:00
|
|
|
use source_map::{LineRangeUtils, SpanUtils};
|
2017-12-24 00:28:58 +09:00
|
|
|
use spanned::Spanned;
|
2017-07-13 18:42:14 +09:00
|
|
|
use string::{rewrite_string, StringFormat};
|
|
|
|
use types::{can_be_overflowed_type, rewrite_path, PathContext};
|
2018-04-29 20:22:48 +08:00
|
|
|
use utils::{
|
chains: prefer to use the next line for an expression, if using the same line would introduce an open block or similar
This problem came to light due to the chains changes, but effects other code too. It only happens rarely, e.g.,
before this fix:
```
match foo {
MacroArgKind::Delimited(ref delim_tok, ref args) => rewrite_delimited_inner(
delim_tok,
args,
).map(|(lhs, inner, rhs)| format!("{}{}{}", lhs, inner, rhs)),
};
```
after:
```
match foo {
MacroArgKind::Delimited(ref delim_tok, ref args) => {
rewrite_delimited_inner(delim_tok, args)
.map(|(lhs, inner, rhs)| format!("{}{}{}", lhs, inner, rhs))
}
}
```
2018-07-11 21:01:40 +12:00
|
|
|
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,
|
2018-04-29 20:22:48 +08:00
|
|
|
};
|
2017-07-03 18:54:41 +09:00
|
|
|
use vertical::rewrite_with_alignment;
|
2017-07-13 18:42:14 +09:00
|
|
|
use visitor::FmtVisitor;
|
2015-04-21 21:01:19 +12:00
|
|
|
|
2015-06-16 17:29:05 +02:00
|
|
|
impl Rewrite for ast::Expr {
|
2017-01-31 08:28:48 +13:00
|
|
|
fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
|
|
|
|
format_expr(self, ExprType::SubExpression, context, shape)
|
2016-05-29 17:58:38 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-29 22:16:04 +09:00
|
|
|
#[derive(Copy, Clone, PartialEq)]
|
2017-06-20 21:35:52 +09:00
|
|
|
pub enum ExprType {
|
2016-05-29 17:58:38 +02:00
|
|
|
Statement,
|
|
|
|
SubExpression,
|
|
|
|
}
|
|
|
|
|
2017-06-20 21:35:52 +09:00
|
|
|
pub fn format_expr(
|
2017-06-12 15:58:58 +12:00
|
|
|
expr: &ast::Expr,
|
|
|
|
expr_type: ExprType,
|
|
|
|
context: &RewriteContext,
|
|
|
|
shape: Shape,
|
|
|
|
) -> Option<String> {
|
2017-07-29 12:51:45 +09:00
|
|
|
skip_out_of_file_lines_range!(context, expr.span);
|
|
|
|
|
2017-05-28 11:41:16 +09:00
|
|
|
if contains_skip(&*expr.attrs) {
|
2017-12-08 13:07:42 +09:00
|
|
|
return Some(context.snippet(expr.span()).to_owned());
|
2017-05-28 11:41:16 +09:00
|
|
|
}
|
2017-07-29 12:51:45 +09:00
|
|
|
|
2017-05-28 11:41:16 +09:00
|
|
|
let expr_rw = match expr.node {
|
2017-07-11 21:53:10 +09:00
|
|
|
ast::ExprKind::Array(ref expr_vec) => rewrite_array(
|
2018-03-26 07:36:44 +09:00
|
|
|
"",
|
2017-11-30 22:13:28 +09:00
|
|
|
&ptr_vec_to_ref_vec(expr_vec),
|
2018-03-26 07:36:44 +09:00
|
|
|
expr.span,
|
2017-07-11 21:53:10 +09:00
|
|
|
context,
|
|
|
|
shape,
|
2018-04-28 15:09:54 +09:00
|
|
|
choose_separator_tactic(context, expr.span),
|
2018-03-26 07:36:44 +09:00
|
|
|
None,
|
2017-07-11 21:53:10 +09:00
|
|
|
),
|
2017-09-28 10:47:01 +09:00
|
|
|
ast::ExprKind::Lit(ref l) => rewrite_literal(context, l, shape),
|
2016-05-29 17:58:38 +02:00
|
|
|
ast::ExprKind::Call(ref callee, ref args) => {
|
2017-08-19 21:47:40 +03:00
|
|
|
let inner_span = mk_sp(callee.span.hi(), expr.span.hi());
|
2017-10-05 20:50:19 +09:00
|
|
|
let callee_str = callee.rewrite(context, shape)?;
|
2017-10-26 16:54:41 +09:00
|
|
|
rewrite_call(context, &callee_str, args, inner_span, shape)
|
2016-05-29 17:58:38 +02:00
|
|
|
}
|
2018-03-08 20:25:18 +09:00
|
|
|
ast::ExprKind::Paren(ref subexpr) => rewrite_paren(context, subexpr, shape, expr.span),
|
2018-05-06 15:22:17 +09:00
|
|
|
ast::ExprKind::Binary(op, ref lhs, ref rhs) => {
|
2017-01-11 12:06:23 +13:00
|
|
|
// FIXME: format comments between operands and operator
|
2018-06-30 19:53:06 +12:00
|
|
|
rewrite_all_pairs(expr, shape, context).or_else(|| {
|
2018-05-06 15:22:17 +09:00
|
|
|
rewrite_pair(
|
|
|
|
&**lhs,
|
|
|
|
&**rhs,
|
2018-06-28 11:50:03 +12:00
|
|
|
PairParts::infix(&format!(" {} ", context.snippet(op.span))),
|
2018-05-06 15:22:17 +09:00
|
|
|
context,
|
|
|
|
shape,
|
|
|
|
context.config.binop_separator(),
|
|
|
|
)
|
|
|
|
})
|
2016-05-29 17:58:38 +02:00
|
|
|
}
|
2017-01-31 08:28:48 +13:00
|
|
|
ast::ExprKind::Unary(ref op, ref subexpr) => rewrite_unary_op(context, op, subexpr, shape),
|
2017-07-11 21:53:10 +09:00
|
|
|
ast::ExprKind::Struct(ref path, ref fields, ref base) => rewrite_struct_lit(
|
|
|
|
context,
|
|
|
|
path,
|
|
|
|
fields,
|
|
|
|
base.as_ref().map(|e| &**e),
|
|
|
|
expr.span,
|
|
|
|
shape,
|
|
|
|
),
|
2017-09-15 22:27:20 +09:00
|
|
|
ast::ExprKind::Tup(ref items) => {
|
2017-10-26 16:54:41 +09:00
|
|
|
rewrite_tuple(context, &ptr_vec_to_ref_vec(items), expr.span, shape)
|
2017-09-15 22:27:20 +09:00
|
|
|
}
|
2017-11-16 16:42:07 +09:00
|
|
|
ast::ExprKind::If(..)
|
|
|
|
| ast::ExprKind::IfLet(..)
|
|
|
|
| ast::ExprKind::ForLoop(..)
|
|
|
|
| ast::ExprKind::Loop(..)
|
|
|
|
| ast::ExprKind::While(..)
|
|
|
|
| ast::ExprKind::WhileLet(..) => to_control_flow(expr, expr_type)
|
2017-07-11 21:53:10 +09:00
|
|
|
.and_then(|control_flow| control_flow.rewrite(context, shape)),
|
2018-05-21 12:18:06 +08:00
|
|
|
ast::ExprKind::Block(ref block, opt_label) => {
|
2017-06-20 21:35:52 +09:00
|
|
|
match expr_type {
|
|
|
|
ExprType::Statement => {
|
|
|
|
if is_unsafe_block(block) {
|
2018-05-21 22:19:26 +08:00
|
|
|
rewrite_block(block, Some(&expr.attrs), opt_label, context, shape)
|
2017-10-20 22:09:45 -07:00
|
|
|
} else if let rw @ Some(_) =
|
2018-06-07 11:15:59 +08:00
|
|
|
rewrite_empty_block(context, block, Some(&expr.attrs), opt_label, "", shape)
|
2017-10-20 22:09:45 -07:00
|
|
|
{
|
2017-06-20 21:35:52 +09:00
|
|
|
// Rewrite block without trying to put it in a single line.
|
2017-08-30 19:27:36 +09:00
|
|
|
rw
|
|
|
|
} else {
|
2017-10-05 20:50:19 +09:00
|
|
|
let prefix = block_prefix(context, block, shape)?;
|
2018-05-21 12:18:06 +08:00
|
|
|
|
2017-10-20 22:09:45 -07:00
|
|
|
rewrite_block_with_visitor(
|
|
|
|
context,
|
2018-05-21 22:19:26 +08:00
|
|
|
&prefix,
|
2017-10-20 22:09:45 -07:00
|
|
|
block,
|
|
|
|
Some(&expr.attrs),
|
2018-06-07 11:15:59 +08:00
|
|
|
opt_label,
|
2017-10-20 22:09:45 -07:00
|
|
|
shape,
|
|
|
|
true,
|
|
|
|
)
|
2017-06-20 21:35:52 +09:00
|
|
|
}
|
|
|
|
}
|
2018-05-21 22:19:26 +08:00
|
|
|
ExprType::SubExpression => {
|
|
|
|
rewrite_block(block, Some(&expr.attrs), opt_label, context, shape)
|
|
|
|
}
|
2017-06-20 21:35:52 +09:00
|
|
|
}
|
|
|
|
}
|
2016-05-29 17:58:38 +02:00
|
|
|
ast::ExprKind::Match(ref cond, ref arms) => {
|
2017-08-05 15:24:12 +09:00
|
|
|
rewrite_match(context, cond, arms, shape, expr.span, &expr.attrs)
|
2016-05-29 17:58:38 +02:00
|
|
|
}
|
|
|
|
ast::ExprKind::Path(ref qself, ref path) => {
|
2017-01-31 08:28:48 +13:00
|
|
|
rewrite_path(context, PathContext::Expr, qself.as_ref(), path, shape)
|
2016-05-29 17:58:38 +02:00
|
|
|
}
|
|
|
|
ast::ExprKind::Assign(ref lhs, ref rhs) => {
|
2017-01-31 08:28:48 +13:00
|
|
|
rewrite_assignment(context, lhs, rhs, None, shape)
|
2016-05-29 17:58:38 +02:00
|
|
|
}
|
|
|
|
ast::ExprKind::AssignOp(ref op, ref lhs, ref rhs) => {
|
2017-01-31 08:28:48 +13:00
|
|
|
rewrite_assignment(context, lhs, rhs, Some(op), shape)
|
2016-05-29 17:58:38 +02:00
|
|
|
}
|
2018-01-29 21:44:26 +09:00
|
|
|
ast::ExprKind::Continue(ref opt_label) => {
|
|
|
|
let id_str = match *opt_label {
|
|
|
|
Some(label) => format!(" {}", label.ident),
|
2016-05-29 17:58:38 +02:00
|
|
|
None => String::new(),
|
|
|
|
};
|
2017-09-19 11:40:20 +09:00
|
|
|
Some(format!("continue{}", id_str))
|
2016-05-29 17:58:38 +02:00
|
|
|
}
|
2018-01-29 21:44:26 +09:00
|
|
|
ast::ExprKind::Break(ref opt_label, ref opt_expr) => {
|
|
|
|
let id_str = match *opt_label {
|
|
|
|
Some(label) => format!(" {}", label.ident),
|
2016-05-29 17:58:38 +02:00
|
|
|
None => String::new(),
|
|
|
|
};
|
2016-12-23 11:13:00 -08:00
|
|
|
|
|
|
|
if let Some(ref expr) = *opt_expr {
|
2017-05-15 22:55:01 +09:00
|
|
|
rewrite_unary_prefix(context, &format!("break{} ", id_str), &**expr, shape)
|
2016-12-23 11:13:00 -08:00
|
|
|
} else {
|
2017-09-19 11:40:20 +09:00
|
|
|
Some(format!("break{}", id_str))
|
2017-08-27 15:31:19 -07:00
|
|
|
}
|
|
|
|
}
|
2017-08-30 19:27:50 +09:00
|
|
|
ast::ExprKind::Yield(ref opt_expr) => if let Some(ref expr) = *opt_expr {
|
|
|
|
rewrite_unary_prefix(context, "yield ", &**expr, shape)
|
|
|
|
} else {
|
2017-09-19 11:40:20 +09:00
|
|
|
Some("yield".to_string())
|
2017-08-30 19:27:50 +09:00
|
|
|
},
|
2018-07-09 23:20:53 +09:00
|
|
|
ast::ExprKind::Closure(capture, asyncness, movability, ref fn_decl, ref body, _) => {
|
2018-01-30 22:14:33 +08:00
|
|
|
closures::rewrite_closure(
|
2018-07-09 23:20:53 +09:00
|
|
|
capture, asyncness, movability, fn_decl, body, expr.span, context, shape,
|
2018-01-30 22:14:33 +08:00
|
|
|
)
|
2016-05-29 17:58:38 +02:00
|
|
|
}
|
2018-04-14 10:20:08 +12:00
|
|
|
ast::ExprKind::Try(..) | ast::ExprKind::Field(..) | ast::ExprKind::MethodCall(..) => {
|
|
|
|
rewrite_chain(expr, context, shape)
|
|
|
|
}
|
2016-05-29 17:58:38 +02:00
|
|
|
ast::ExprKind::Mac(ref mac) => {
|
2017-11-11 23:14:24 +09:00
|
|
|
rewrite_macro(mac, None, context, shape, MacroPosition::Expression).or_else(|| {
|
|
|
|
wrap_str(
|
2017-12-08 13:07:42 +09:00
|
|
|
context.snippet(expr.span).to_owned(),
|
2017-11-11 23:14:24 +09:00
|
|
|
context.config.max_width(),
|
|
|
|
shape,
|
|
|
|
)
|
|
|
|
})
|
2016-05-29 17:58:38 +02:00
|
|
|
}
|
2017-09-19 11:40:20 +09:00
|
|
|
ast::ExprKind::Ret(None) => Some("return".to_owned()),
|
2016-05-29 17:58:38 +02:00
|
|
|
ast::ExprKind::Ret(Some(ref expr)) => {
|
2017-05-15 22:55:01 +09:00
|
|
|
rewrite_unary_prefix(context, "return ", &**expr, shape)
|
2016-05-29 17:58:38 +02:00
|
|
|
}
|
2017-05-15 22:55:01 +09:00
|
|
|
ast::ExprKind::Box(ref expr) => rewrite_unary_prefix(context, "box ", &**expr, shape),
|
2016-05-29 17:58:38 +02:00
|
|
|
ast::ExprKind::AddrOf(mutability, ref expr) => {
|
2017-01-31 08:28:48 +13:00
|
|
|
rewrite_expr_addrof(context, mutability, expr, shape)
|
2016-05-29 17:58:38 +02:00
|
|
|
}
|
2017-09-15 12:10:30 +09:00
|
|
|
ast::ExprKind::Cast(ref expr, ref ty) => rewrite_pair(
|
|
|
|
&**expr,
|
|
|
|
&**ty,
|
2018-06-28 11:50:03 +12:00
|
|
|
PairParts::infix(" as "),
|
2017-09-15 12:10:30 +09:00
|
|
|
context,
|
|
|
|
shape,
|
|
|
|
SeparatorPlace::Front,
|
|
|
|
),
|
|
|
|
ast::ExprKind::Type(ref expr, ref ty) => rewrite_pair(
|
|
|
|
&**expr,
|
|
|
|
&**ty,
|
2018-06-28 11:50:03 +12:00
|
|
|
PairParts::infix(": "),
|
2017-09-15 12:10:30 +09:00
|
|
|
context,
|
|
|
|
shape,
|
2017-09-15 15:04:30 +09:00
|
|
|
SeparatorPlace::Back,
|
2017-09-15 12:10:30 +09:00
|
|
|
),
|
2016-05-29 17:58:38 +02:00
|
|
|
ast::ExprKind::Index(ref expr, ref index) => {
|
2017-01-31 08:28:48 +13:00
|
|
|
rewrite_index(&**expr, &**index, context, shape)
|
2016-05-29 17:58:38 +02:00
|
|
|
}
|
2018-05-18 16:35:09 +12:00
|
|
|
ast::ExprKind::Repeat(ref expr, ref repeats) => rewrite_pair(
|
|
|
|
&**expr,
|
2018-05-23 06:04:14 +09:00
|
|
|
&*repeats.value,
|
2018-05-18 16:35:09 +12:00
|
|
|
PairParts::new("[", "; ", "]"),
|
|
|
|
context,
|
|
|
|
shape,
|
|
|
|
SeparatorPlace::Back,
|
|
|
|
),
|
2016-05-29 17:58:38 +02:00
|
|
|
ast::ExprKind::Range(ref lhs, ref rhs, limits) => {
|
|
|
|
let delim = match limits {
|
|
|
|
ast::RangeLimits::HalfOpen => "..",
|
2017-09-27 22:19:10 +02:00
|
|
|
ast::RangeLimits::Closed => "..=",
|
2016-05-29 17:58:38 +02:00
|
|
|
};
|
|
|
|
|
2017-07-04 20:21:49 +09:00
|
|
|
fn needs_space_before_range(context: &RewriteContext, lhs: &ast::Expr) -> bool {
|
|
|
|
match lhs.node {
|
2017-07-11 21:53:10 +09:00
|
|
|
ast::ExprKind::Lit(ref lit) => match lit.node {
|
|
|
|
ast::LitKind::FloatUnsuffixed(..) => {
|
|
|
|
context.snippet(lit.span).ends_with('.')
|
2017-07-04 20:21:49 +09:00
|
|
|
}
|
2017-07-11 21:53:10 +09:00
|
|
|
_ => false,
|
|
|
|
},
|
2017-07-04 20:21:49 +09:00
|
|
|
_ => false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-16 17:11:50 +09:00
|
|
|
fn needs_space_after_range(rhs: &ast::Expr) -> bool {
|
|
|
|
match rhs.node {
|
|
|
|
// Don't format `.. ..` into `....`, which is invalid.
|
|
|
|
//
|
|
|
|
// This check is unnecessary for `lhs`, because a range
|
|
|
|
// starting from another range needs parentheses as `(x ..) ..`
|
|
|
|
// (`x .. ..` is a range from `x` to `..`).
|
|
|
|
ast::ExprKind::Range(None, _, _) => true,
|
|
|
|
_ => false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let default_sp_delim = |lhs: Option<&ast::Expr>, rhs: Option<&ast::Expr>| {
|
|
|
|
let space_if = |b: bool| if b { " " } else { "" };
|
|
|
|
|
|
|
|
format!(
|
|
|
|
"{}{}{}",
|
|
|
|
lhs.map(|lhs| space_if(needs_space_before_range(context, lhs)))
|
|
|
|
.unwrap_or(""),
|
|
|
|
delim,
|
|
|
|
rhs.map(|rhs| space_if(needs_space_after_range(rhs)))
|
|
|
|
.unwrap_or(""),
|
|
|
|
)
|
|
|
|
};
|
|
|
|
|
2016-05-29 17:58:38 +02:00
|
|
|
match (lhs.as_ref().map(|x| &**x), rhs.as_ref().map(|x| &**x)) {
|
2017-08-29 22:16:04 +09:00
|
|
|
(Some(lhs), Some(rhs)) => {
|
2017-05-16 15:47:09 +07:00
|
|
|
let sp_delim = if context.config.spaces_around_ranges() {
|
2016-09-17 01:44:51 +02:00
|
|
|
format!(" {} ", delim)
|
|
|
|
} else {
|
2018-04-16 17:11:50 +09:00
|
|
|
default_sp_delim(Some(lhs), Some(rhs))
|
2016-09-17 01:44:51 +02:00
|
|
|
};
|
2017-09-15 12:10:30 +09:00
|
|
|
rewrite_pair(
|
|
|
|
&*lhs,
|
|
|
|
&*rhs,
|
2018-06-28 11:50:03 +12:00
|
|
|
PairParts::infix(&sp_delim),
|
2017-09-15 12:10:30 +09:00
|
|
|
context,
|
|
|
|
shape,
|
2018-01-16 17:39:21 +13:00
|
|
|
context.config.binop_separator(),
|
2017-09-15 12:10:30 +09:00
|
|
|
)
|
2016-05-29 17:58:38 +02:00
|
|
|
}
|
2017-08-29 22:16:04 +09:00
|
|
|
(None, Some(rhs)) => {
|
2017-05-16 15:47:09 +07:00
|
|
|
let sp_delim = if context.config.spaces_around_ranges() {
|
2016-09-17 01:44:51 +02:00
|
|
|
format!("{} ", delim)
|
|
|
|
} else {
|
2018-04-16 17:11:50 +09:00
|
|
|
default_sp_delim(None, Some(rhs))
|
2016-09-17 01:44:51 +02:00
|
|
|
};
|
2017-08-29 22:16:04 +09:00
|
|
|
rewrite_unary_prefix(context, &sp_delim, &*rhs, shape)
|
2016-05-29 17:58:38 +02:00
|
|
|
}
|
2017-08-29 22:16:04 +09:00
|
|
|
(Some(lhs), None) => {
|
2017-05-16 15:47:09 +07:00
|
|
|
let sp_delim = if context.config.spaces_around_ranges() {
|
2016-09-17 01:44:51 +02:00
|
|
|
format!(" {}", delim)
|
|
|
|
} else {
|
2018-04-16 17:11:50 +09:00
|
|
|
default_sp_delim(Some(lhs), None)
|
2016-09-17 01:44:51 +02:00
|
|
|
};
|
2017-08-29 22:16:04 +09:00
|
|
|
rewrite_unary_suffix(context, &sp_delim, &*lhs, shape)
|
2016-05-29 17:58:38 +02:00
|
|
|
}
|
2017-12-08 13:07:42 +09:00
|
|
|
(None, None) => Some(delim.to_owned()),
|
2015-09-23 22:51:37 -07:00
|
|
|
}
|
2016-05-29 17:58:38 +02:00
|
|
|
}
|
|
|
|
// We do not format these expressions yet, but they should still
|
|
|
|
// satisfy our width restrictions.
|
2018-04-06 23:09:45 +09:00
|
|
|
ast::ExprKind::InlineAsm(..) => Some(context.snippet(expr.span).to_owned()),
|
2017-05-13 07:28:48 +09:00
|
|
|
ast::ExprKind::Catch(ref block) => {
|
2018-06-07 11:15:59 +08:00
|
|
|
if let rw @ Some(_) = rewrite_single_line_block(
|
|
|
|
context,
|
|
|
|
"do catch ",
|
|
|
|
block,
|
|
|
|
Some(&expr.attrs),
|
|
|
|
None,
|
|
|
|
shape,
|
|
|
|
) {
|
2017-08-30 19:27:36 +09:00
|
|
|
rw
|
|
|
|
} else {
|
|
|
|
// 9 = `do catch `
|
2018-05-14 21:58:57 +09:00
|
|
|
let budget = shape.width.saturating_sub(9);
|
2017-08-30 19:27:36 +09:00
|
|
|
Some(format!(
|
|
|
|
"{}{}",
|
|
|
|
"do catch ",
|
2017-10-20 22:09:45 -07:00
|
|
|
rewrite_block(
|
|
|
|
block,
|
|
|
|
Some(&expr.attrs),
|
2018-05-21 22:19:26 +08:00
|
|
|
None,
|
2017-10-20 22:09:45 -07:00
|
|
|
context,
|
|
|
|
Shape::legacy(budget, shape.indent)
|
|
|
|
)?
|
2017-08-30 19:27:36 +09:00
|
|
|
))
|
2017-05-13 07:28:48 +09:00
|
|
|
}
|
|
|
|
}
|
2018-05-30 00:22:49 +01:00
|
|
|
// FIXME(#2743)
|
|
|
|
ast::ExprKind::ObsoleteInPlace(..) => unimplemented!(),
|
2018-07-29 08:45:31 -07:00
|
|
|
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,
|
|
|
|
) {
|
2018-07-29 07:37:24 -07:00
|
|
|
rw
|
|
|
|
} else {
|
|
|
|
// 6 = `async `
|
|
|
|
let budget = shape.width.saturating_sub(6);
|
|
|
|
Some(format!(
|
2018-07-29 08:45:31 -07:00
|
|
|
"{}{}{}",
|
2018-07-29 07:37:24 -07:00
|
|
|
"async ",
|
2018-07-29 08:45:31 -07:00
|
|
|
mover,
|
2018-07-29 07:37:24 -07:00
|
|
|
rewrite_block(
|
|
|
|
block,
|
|
|
|
Some(&expr.attrs),
|
|
|
|
None,
|
|
|
|
context,
|
|
|
|
Shape::legacy(budget, shape.indent)
|
|
|
|
)?
|
|
|
|
))
|
|
|
|
}
|
|
|
|
}
|
2016-05-29 17:58:38 +02:00
|
|
|
};
|
2017-07-20 23:58:00 +09:00
|
|
|
|
|
|
|
expr_rw
|
2017-11-29 17:37:51 +09:00
|
|
|
.and_then(|expr_str| recover_comment_removed(expr_str, expr.span, context))
|
2017-07-20 23:58:00 +09:00
|
|
|
.and_then(|expr_str| {
|
2017-08-11 17:52:13 +09:00
|
|
|
let attrs = outer_attributes(&expr.attrs);
|
2017-10-05 20:50:19 +09:00
|
|
|
let attrs_str = attrs.rewrite(context, shape)?;
|
2017-08-11 17:52:13 +09:00
|
|
|
let span = mk_sp(
|
2017-08-19 21:47:40 +03:00
|
|
|
attrs.last().map_or(expr.span.lo(), |attr| attr.span.hi()),
|
|
|
|
expr.span.lo(),
|
2017-08-11 17:52:13 +09:00
|
|
|
);
|
|
|
|
combine_strs_with_missing_comments(context, &attrs_str, &expr_str, span, shape, false)
|
2017-07-20 23:58:00 +09:00
|
|
|
})
|
2015-06-16 17:29:05 +02:00
|
|
|
}
|
2015-04-21 21:01:19 +12:00
|
|
|
|
2017-11-30 22:13:28 +09:00
|
|
|
pub fn rewrite_array<T: Rewrite + Spanned + ToExpr>(
|
2018-03-26 07:36:44 +09:00
|
|
|
name: &str,
|
2017-11-30 22:13:28 +09:00
|
|
|
exprs: &[&T],
|
2017-06-12 15:58:58 +12:00
|
|
|
span: Span,
|
|
|
|
context: &RewriteContext,
|
|
|
|
shape: Shape,
|
2018-03-26 07:36:44 +09:00
|
|
|
force_separator_tactic: Option<SeparatorTactic>,
|
|
|
|
delim_token: Option<DelimToken>,
|
2017-11-30 22:13:28 +09:00
|
|
|
) -> Option<String> {
|
2018-03-26 07:36:44 +09:00
|
|
|
overflow::rewrite_with_square_brackets(
|
|
|
|
context,
|
|
|
|
name,
|
|
|
|
exprs,
|
|
|
|
shape,
|
|
|
|
span,
|
|
|
|
force_separator_tactic,
|
|
|
|
delim_token,
|
|
|
|
)
|
2017-12-04 12:06:46 +09:00
|
|
|
}
|
|
|
|
|
2017-06-20 21:34:19 +09:00
|
|
|
fn rewrite_empty_block(
|
|
|
|
context: &RewriteContext,
|
|
|
|
block: &ast::Block,
|
2017-10-20 22:09:45 -07:00
|
|
|
attrs: Option<&[ast::Attribute]>,
|
2018-06-07 11:15:59 +08:00
|
|
|
label: Option<ast::Label>,
|
2017-10-20 22:09:45 -07:00
|
|
|
prefix: &str,
|
2017-06-20 21:34:19 +09:00
|
|
|
shape: Shape,
|
|
|
|
) -> Option<String> {
|
2018-06-07 11:15:59 +08:00
|
|
|
let label_str = rewrite_label(label);
|
2017-10-20 22:09:45 -07:00
|
|
|
if attrs.map_or(false, |a| !inner_attributes(a).is_empty()) {
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
|
2018-08-23 17:14:19 -04:00
|
|
|
if block.stmts.is_empty()
|
|
|
|
&& !block_contains_comment(block, context.source_map)
|
|
|
|
&& shape.width >= 2
|
2017-06-20 21:34:19 +09:00
|
|
|
{
|
2018-06-07 11:15:59 +08:00
|
|
|
return Some(format!("{}{}{{}}", prefix, label_str));
|
2017-06-20 21:34:19 +09:00
|
|
|
}
|
2016-06-09 00:43:08 +09:00
|
|
|
|
2017-06-20 21:34:19 +09:00
|
|
|
// If a block contains only a single-line comment, then leave it on one line.
|
|
|
|
let user_str = context.snippet(block.span);
|
|
|
|
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();
|
2018-05-06 15:22:29 +09:00
|
|
|
if block.stmts.is_empty()
|
|
|
|
&& !comment_str.contains('\n')
|
|
|
|
&& !comment_str.starts_with("//")
|
2017-09-15 12:10:58 +09:00
|
|
|
&& comment_str.len() + 4 <= shape.width
|
2017-06-12 15:58:58 +12:00
|
|
|
{
|
2018-06-07 11:15:59 +08:00
|
|
|
return Some(format!("{}{}{{ {} }}", prefix, label_str, comment_str));
|
2017-01-16 16:37:58 +13:00
|
|
|
}
|
2017-06-20 21:34:19 +09:00
|
|
|
}
|
2017-01-16 16:37:58 +13:00
|
|
|
|
2017-06-20 21:34:19 +09:00
|
|
|
None
|
|
|
|
}
|
|
|
|
|
|
|
|
fn block_prefix(context: &RewriteContext, block: &ast::Block, shape: Shape) -> Option<String> {
|
|
|
|
Some(match block.rules {
|
|
|
|
ast::BlockCheckMode::Unsafe(..) => {
|
|
|
|
let snippet = context.snippet(block.span);
|
2017-10-05 20:50:19 +09:00
|
|
|
let open_pos = snippet.find_uncommented("{")?;
|
2017-06-20 21:34:19 +09:00
|
|
|
// Extract comment between unsafe and block start.
|
|
|
|
let trimmed = &snippet[6..open_pos].trim();
|
|
|
|
|
|
|
|
if !trimmed.is_empty() {
|
|
|
|
// 9 = "unsafe {".len(), 7 = "unsafe ".len()
|
2017-10-05 20:50:19 +09:00
|
|
|
let budget = shape.width.checked_sub(9)?;
|
2017-06-20 21:34:19 +09:00
|
|
|
format!(
|
|
|
|
"unsafe {} ",
|
2017-10-05 20:50:19 +09:00
|
|
|
rewrite_comment(
|
2017-06-20 21:34:19 +09:00
|
|
|
trimmed,
|
|
|
|
true,
|
|
|
|
Shape::legacy(budget, shape.indent + 7),
|
|
|
|
context.config,
|
2017-10-05 20:50:19 +09:00
|
|
|
)?
|
2017-06-20 21:34:19 +09:00
|
|
|
)
|
|
|
|
} else {
|
|
|
|
"unsafe ".to_owned()
|
2017-01-16 16:37:58 +13:00
|
|
|
}
|
2015-08-16 16:13:55 +12:00
|
|
|
}
|
2017-06-20 21:34:19 +09:00
|
|
|
ast::BlockCheckMode::Default => String::new(),
|
|
|
|
})
|
|
|
|
}
|
2015-08-16 16:13:55 +12:00
|
|
|
|
2017-06-20 21:34:19 +09:00
|
|
|
fn rewrite_single_line_block(
|
|
|
|
context: &RewriteContext,
|
|
|
|
prefix: &str,
|
|
|
|
block: &ast::Block,
|
2017-10-20 22:09:45 -07:00
|
|
|
attrs: Option<&[ast::Attribute]>,
|
2018-06-07 11:15:59 +08:00
|
|
|
label: Option<ast::Label>,
|
2017-06-20 21:34:19 +09:00
|
|
|
shape: Shape,
|
|
|
|
) -> Option<String> {
|
2018-08-23 17:10:46 -04:00
|
|
|
if is_simple_block(block, attrs, context.source_map) {
|
2017-12-19 09:41:05 +09:00
|
|
|
let expr_shape = shape.offset_left(last_line_width(prefix))?;
|
2017-10-05 20:50:19 +09:00
|
|
|
let expr_str = block.stmts[0].rewrite(context, expr_shape)?;
|
2018-06-07 11:15:59 +08:00
|
|
|
let label_str = rewrite_label(label);
|
|
|
|
let result = format!("{}{}{{ {} }}", prefix, label_str, expr_str);
|
2017-06-20 21:34:19 +09:00
|
|
|
if result.len() <= shape.width && !result.contains('\n') {
|
|
|
|
return Some(result);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
None
|
|
|
|
}
|
2015-08-01 14:22:31 +02:00
|
|
|
|
2017-11-30 06:12:32 +09:00
|
|
|
pub fn rewrite_block_with_visitor(
|
2017-06-20 21:34:19 +09:00
|
|
|
context: &RewriteContext,
|
|
|
|
prefix: &str,
|
|
|
|
block: &ast::Block,
|
2017-10-20 22:09:45 -07:00
|
|
|
attrs: Option<&[ast::Attribute]>,
|
2018-06-07 11:15:59 +08:00
|
|
|
label: Option<ast::Label>,
|
2017-06-20 21:34:19 +09:00
|
|
|
shape: Shape,
|
2017-11-30 06:40:29 +09:00
|
|
|
has_braces: bool,
|
2017-06-20 21:34:19 +09:00
|
|
|
) -> Option<String> {
|
2018-06-07 11:15:59 +08:00
|
|
|
if let rw @ Some(_) = rewrite_empty_block(context, block, attrs, label, prefix, shape) {
|
2017-06-20 21:34:19 +09:00
|
|
|
return rw;
|
|
|
|
}
|
|
|
|
|
2017-12-07 13:53:10 +09:00
|
|
|
let mut visitor = FmtVisitor::from_context(context);
|
2017-06-20 21:34:19 +09:00
|
|
|
visitor.block_indent = shape.indent;
|
2018-03-25 20:20:50 +09:00
|
|
|
visitor.is_if_else_block = context.is_if_else_block();
|
2017-06-20 21:34:19 +09:00
|
|
|
match block.rules {
|
|
|
|
ast::BlockCheckMode::Unsafe(..) => {
|
|
|
|
let snippet = context.snippet(block.span);
|
2017-10-05 20:50:19 +09:00
|
|
|
let open_pos = snippet.find_uncommented("{")?;
|
2017-08-19 21:47:40 +03:00
|
|
|
visitor.last_pos = block.span.lo() + BytePos(open_pos as u32)
|
2017-06-20 21:34:19 +09:00
|
|
|
}
|
2017-08-19 21:47:40 +03:00
|
|
|
ast::BlockCheckMode::Default => visitor.last_pos = block.span.lo(),
|
2017-06-20 21:34:19 +09:00
|
|
|
}
|
|
|
|
|
2017-10-20 22:09:45 -07:00
|
|
|
let inner_attrs = attrs.map(inner_attributes);
|
2018-06-07 11:15:59 +08:00
|
|
|
let label_str = rewrite_label(label);
|
2017-10-20 22:09:45 -07:00
|
|
|
visitor.visit_block(block, inner_attrs.as_ref().map(|a| &**a), has_braces);
|
2018-06-07 11:15:59 +08:00
|
|
|
Some(format!("{}{}{}", prefix, label_str, visitor.buffer))
|
2017-06-20 21:34:19 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Rewrite for ast::Block {
|
|
|
|
fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
|
2018-05-21 22:19:26 +08:00
|
|
|
rewrite_block(self, None, None, context, shape)
|
2017-10-20 22:09:45 -07:00
|
|
|
}
|
|
|
|
}
|
2017-06-20 21:34:19 +09:00
|
|
|
|
2017-10-20 22:09:45 -07:00
|
|
|
fn rewrite_block(
|
|
|
|
block: &ast::Block,
|
|
|
|
attrs: Option<&[ast::Attribute]>,
|
2018-05-21 22:19:26 +08:00
|
|
|
label: Option<ast::Label>,
|
2017-10-20 22:09:45 -07:00
|
|
|
context: &RewriteContext,
|
|
|
|
shape: Shape,
|
|
|
|
) -> Option<String> {
|
2018-06-07 11:15:59 +08:00
|
|
|
let prefix = block_prefix(context, block, shape)?;
|
2017-09-01 22:52:54 +09:00
|
|
|
|
2017-10-20 22:09:45 -07:00
|
|
|
// shape.width is used only for the single line case: either the empty block `{}`,
|
|
|
|
// or an unsafe expression `unsafe { e }`.
|
2018-06-07 11:15:59 +08:00
|
|
|
if let rw @ Some(_) = rewrite_empty_block(context, block, attrs, label, &prefix, shape) {
|
2017-10-20 22:09:45 -07:00
|
|
|
return rw;
|
|
|
|
}
|
|
|
|
|
2018-06-07 11:15:59 +08:00
|
|
|
let result = rewrite_block_with_visitor(context, &prefix, block, attrs, label, shape, true);
|
2017-10-20 22:09:45 -07:00
|
|
|
if let Some(ref result_str) = result {
|
|
|
|
if result_str.lines().count() <= 3 {
|
2018-06-07 11:15:59 +08:00
|
|
|
if let rw @ Some(_) =
|
|
|
|
rewrite_single_line_block(context, &prefix, block, attrs, label, shape)
|
|
|
|
{
|
2017-10-20 22:09:45 -07:00
|
|
|
return rw;
|
2017-09-01 22:52:54 +09:00
|
|
|
}
|
2017-06-20 21:34:19 +09:00
|
|
|
}
|
2015-07-13 21:51:56 +02:00
|
|
|
}
|
2017-10-20 22:09:45 -07:00
|
|
|
|
|
|
|
result
|
2015-07-13 21:51:56 +02:00
|
|
|
}
|
|
|
|
|
2015-11-19 02:08:17 -06:00
|
|
|
impl Rewrite for ast::Stmt {
|
2017-01-31 08:28:48 +13:00
|
|
|
fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
|
2017-07-29 12:51:45 +09:00
|
|
|
skip_out_of_file_lines_range!(context, self.span());
|
|
|
|
|
2016-01-10 15:12:15 +01:00
|
|
|
let result = match self.node {
|
2017-03-22 09:05:50 +13:00
|
|
|
ast::StmtKind::Local(ref local) => local.rewrite(context, shape),
|
2017-07-10 02:24:59 +09:00
|
|
|
ast::StmtKind::Expr(ref ex) | ast::StmtKind::Semi(ref ex) => {
|
2017-07-11 22:41:38 +09:00
|
|
|
let suffix = if semicolon_for_stmt(context, self) {
|
|
|
|
";"
|
|
|
|
} else {
|
|
|
|
""
|
|
|
|
};
|
2015-11-19 02:08:17 -06:00
|
|
|
|
2017-10-05 20:50:19 +09:00
|
|
|
let shape = shape.sub_width(suffix.len())?;
|
2017-09-03 08:09:37 +09:00
|
|
|
format_expr(ex, ExprType::Statement, context, shape).map(|s| s + suffix)
|
2015-11-19 02:08:17 -06:00
|
|
|
}
|
2017-07-10 02:24:59 +09:00
|
|
|
ast::StmtKind::Mac(..) | ast::StmtKind::Item(..) => None,
|
2016-01-10 15:12:15 +01:00
|
|
|
};
|
2017-09-18 23:30:59 +09:00
|
|
|
result.and_then(|res| recover_comment_removed(res, self.span(), context))
|
2015-11-19 02:08:17 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-15 23:26:32 +09:00
|
|
|
// Rewrite condition if the given expression has one.
|
2017-11-13 15:26:33 +13:00
|
|
|
pub fn rewrite_cond(context: &RewriteContext, expr: &ast::Expr, shape: Shape) -> Option<String> {
|
2017-06-15 23:26:32 +09:00
|
|
|
match expr.node {
|
|
|
|
ast::ExprKind::Match(ref cond, _) => {
|
|
|
|
// `match `cond` {`
|
2017-11-13 16:42:29 +09:00
|
|
|
let cond_shape = match context.config.indent_style() {
|
|
|
|
IndentStyle::Visual => shape.shrink_left(6).and_then(|s| s.sub_width(2))?,
|
|
|
|
IndentStyle::Block => shape.offset_left(8)?,
|
2017-06-15 23:26:32 +09:00
|
|
|
};
|
|
|
|
cond.rewrite(context, cond_shape)
|
|
|
|
}
|
2017-07-11 21:53:10 +09:00
|
|
|
_ => to_control_flow(expr, ExprType::SubExpression).and_then(|control_flow| {
|
|
|
|
let alt_block_sep =
|
|
|
|
String::from("\n") + &shape.indent.block_only().to_string(context.config);
|
|
|
|
control_flow
|
|
|
|
.rewrite_cond(context, shape, &alt_block_sep)
|
|
|
|
.and_then(|rw| Some(rw.0))
|
|
|
|
}),
|
2017-06-15 23:26:32 +09:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-11 14:34:42 +13:00
|
|
|
// Abstraction over control flow expressions
|
2017-01-27 09:14:26 +13:00
|
|
|
#[derive(Debug)]
|
2017-01-11 14:34:42 +13:00
|
|
|
struct ControlFlow<'a> {
|
2015-07-20 23:29:25 +02:00
|
|
|
cond: Option<&'a ast::Expr>,
|
|
|
|
block: &'a ast::Block,
|
2017-01-11 14:34:42 +13:00
|
|
|
else_block: Option<&'a ast::Expr>,
|
2018-01-29 21:44:26 +09:00
|
|
|
label: Option<ast::Label>,
|
2018-03-08 12:56:28 +09:00
|
|
|
pats: Vec<&'a ast::Pat>,
|
2015-07-20 23:29:25 +02:00
|
|
|
keyword: &'a str,
|
|
|
|
matcher: &'a str,
|
|
|
|
connector: &'a str,
|
2017-01-11 14:34:42 +13:00
|
|
|
allow_single_line: bool,
|
|
|
|
// True if this is an `if` expression in an `else if` :-( hacky
|
|
|
|
nested_if: bool,
|
|
|
|
span: Span,
|
2015-07-20 23:29:25 +02:00
|
|
|
}
|
|
|
|
|
2017-12-12 13:48:12 +09:00
|
|
|
fn to_control_flow(expr: &ast::Expr, expr_type: ExprType) -> Option<ControlFlow> {
|
2017-06-15 23:26:32 +09:00
|
|
|
match expr.node {
|
2017-07-11 21:53:10 +09:00
|
|
|
ast::ExprKind::If(ref cond, ref if_block, ref else_block) => Some(ControlFlow::new_if(
|
|
|
|
cond,
|
2018-03-08 12:56:28 +09:00
|
|
|
vec![],
|
2017-07-11 21:53:10 +09:00
|
|
|
if_block,
|
|
|
|
else_block.as_ref().map(|e| &**e),
|
|
|
|
expr_type == ExprType::SubExpression,
|
|
|
|
false,
|
|
|
|
expr.span,
|
|
|
|
)),
|
2017-06-15 23:26:32 +09:00
|
|
|
ast::ExprKind::IfLet(ref pat, ref cond, ref if_block, ref else_block) => {
|
|
|
|
Some(ControlFlow::new_if(
|
|
|
|
cond,
|
2018-03-08 12:56:28 +09:00
|
|
|
ptr_vec_to_ref_vec(pat),
|
2017-06-15 23:26:32 +09:00
|
|
|
if_block,
|
|
|
|
else_block.as_ref().map(|e| &**e),
|
|
|
|
expr_type == ExprType::SubExpression,
|
|
|
|
false,
|
|
|
|
expr.span,
|
|
|
|
))
|
|
|
|
}
|
|
|
|
ast::ExprKind::ForLoop(ref pat, ref cond, ref block, label) => {
|
|
|
|
Some(ControlFlow::new_for(pat, cond, block, label, expr.span))
|
|
|
|
}
|
2017-07-11 21:53:10 +09:00
|
|
|
ast::ExprKind::Loop(ref block, label) => {
|
|
|
|
Some(ControlFlow::new_loop(block, label, expr.span))
|
|
|
|
}
|
2018-03-08 12:56:28 +09:00
|
|
|
ast::ExprKind::While(ref cond, ref block, label) => Some(ControlFlow::new_while(
|
|
|
|
vec![],
|
|
|
|
cond,
|
|
|
|
block,
|
|
|
|
label,
|
|
|
|
expr.span,
|
|
|
|
)),
|
2017-07-11 21:53:10 +09:00
|
|
|
ast::ExprKind::WhileLet(ref pat, ref cond, ref block, label) => Some(
|
2018-03-08 12:56:28 +09:00
|
|
|
ControlFlow::new_while(ptr_vec_to_ref_vec(pat), cond, block, label, expr.span),
|
2017-07-11 21:53:10 +09:00
|
|
|
),
|
2017-06-15 23:26:32 +09:00
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-08 12:56:28 +09:00
|
|
|
fn choose_matcher(pats: &[&ast::Pat]) -> &'static str {
|
|
|
|
if pats.is_empty() {
|
|
|
|
""
|
|
|
|
} else {
|
|
|
|
"let"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-11 14:34:42 +13:00
|
|
|
impl<'a> ControlFlow<'a> {
|
2017-06-12 15:58:58 +12:00
|
|
|
fn new_if(
|
|
|
|
cond: &'a ast::Expr,
|
2018-03-08 12:56:28 +09:00
|
|
|
pats: Vec<&'a ast::Pat>,
|
2017-06-12 15:58:58 +12:00
|
|
|
block: &'a ast::Block,
|
|
|
|
else_block: Option<&'a ast::Expr>,
|
|
|
|
allow_single_line: bool,
|
|
|
|
nested_if: bool,
|
|
|
|
span: Span,
|
|
|
|
) -> ControlFlow<'a> {
|
2018-03-08 12:56:28 +09:00
|
|
|
let matcher = choose_matcher(&pats);
|
2017-01-11 14:34:42 +13:00
|
|
|
ControlFlow {
|
|
|
|
cond: Some(cond),
|
2018-01-22 13:05:18 +09:00
|
|
|
block,
|
|
|
|
else_block,
|
2017-01-11 14:34:42 +13:00
|
|
|
label: None,
|
2018-03-06 20:02:04 +09:00
|
|
|
pats,
|
2017-01-11 14:34:42 +13:00
|
|
|
keyword: "if",
|
2018-03-06 20:02:04 +09:00
|
|
|
matcher,
|
2017-01-11 14:34:42 +13:00
|
|
|
connector: " =",
|
2018-01-22 13:05:18 +09:00
|
|
|
allow_single_line,
|
|
|
|
nested_if,
|
|
|
|
span,
|
2017-01-11 14:34:42 +13:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-29 21:44:26 +09:00
|
|
|
fn new_loop(block: &'a ast::Block, label: Option<ast::Label>, span: Span) -> ControlFlow<'a> {
|
2017-01-11 14:34:42 +13:00
|
|
|
ControlFlow {
|
2015-07-20 23:29:25 +02:00
|
|
|
cond: None,
|
2018-01-22 13:05:18 +09:00
|
|
|
block,
|
2017-01-11 14:34:42 +13:00
|
|
|
else_block: None,
|
2018-01-22 13:05:18 +09:00
|
|
|
label,
|
2018-03-08 12:56:28 +09:00
|
|
|
pats: vec![],
|
2015-07-20 23:29:25 +02:00
|
|
|
keyword: "loop",
|
|
|
|
matcher: "",
|
|
|
|
connector: "",
|
2017-01-11 14:34:42 +13:00
|
|
|
allow_single_line: false,
|
|
|
|
nested_if: false,
|
2018-01-22 13:05:18 +09:00
|
|
|
span,
|
2015-07-20 23:29:25 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-12 15:58:58 +12:00
|
|
|
fn new_while(
|
2018-03-08 12:56:28 +09:00
|
|
|
pats: Vec<&'a ast::Pat>,
|
2017-06-12 15:58:58 +12:00
|
|
|
cond: &'a ast::Expr,
|
|
|
|
block: &'a ast::Block,
|
2018-01-29 21:44:26 +09:00
|
|
|
label: Option<ast::Label>,
|
2017-06-12 15:58:58 +12:00
|
|
|
span: Span,
|
|
|
|
) -> ControlFlow<'a> {
|
2018-03-08 12:56:28 +09:00
|
|
|
let matcher = choose_matcher(&pats);
|
2017-01-11 14:34:42 +13:00
|
|
|
ControlFlow {
|
2015-07-20 23:29:25 +02:00
|
|
|
cond: Some(cond),
|
2018-01-22 13:05:18 +09:00
|
|
|
block,
|
2017-01-11 14:34:42 +13:00
|
|
|
else_block: None,
|
2018-01-22 13:05:18 +09:00
|
|
|
label,
|
2018-03-06 20:02:04 +09:00
|
|
|
pats,
|
2017-01-11 14:34:42 +13:00
|
|
|
keyword: "while",
|
2018-03-06 20:02:04 +09:00
|
|
|
matcher,
|
2015-07-20 23:29:25 +02:00
|
|
|
connector: " =",
|
2017-01-11 14:34:42 +13:00
|
|
|
allow_single_line: false,
|
|
|
|
nested_if: false,
|
2018-01-22 13:05:18 +09:00
|
|
|
span,
|
2015-07-20 23:29:25 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-12 15:58:58 +12:00
|
|
|
fn new_for(
|
|
|
|
pat: &'a ast::Pat,
|
|
|
|
cond: &'a ast::Expr,
|
|
|
|
block: &'a ast::Block,
|
2018-01-29 21:44:26 +09:00
|
|
|
label: Option<ast::Label>,
|
2017-06-12 15:58:58 +12:00
|
|
|
span: Span,
|
|
|
|
) -> ControlFlow<'a> {
|
2017-01-11 14:34:42 +13:00
|
|
|
ControlFlow {
|
2015-07-20 23:29:25 +02:00
|
|
|
cond: Some(cond),
|
2018-01-22 13:05:18 +09:00
|
|
|
block,
|
2017-01-11 14:34:42 +13:00
|
|
|
else_block: None,
|
2018-01-22 13:05:18 +09:00
|
|
|
label,
|
2018-03-08 12:56:28 +09:00
|
|
|
pats: vec![pat],
|
2017-01-11 14:34:42 +13:00
|
|
|
keyword: "for",
|
2015-07-20 23:29:25 +02:00
|
|
|
matcher: "",
|
|
|
|
connector: " in",
|
2017-01-11 14:34:42 +13:00
|
|
|
allow_single_line: false,
|
|
|
|
nested_if: false,
|
2018-01-22 13:05:18 +09:00
|
|
|
span,
|
2015-07-20 23:29:25 +02:00
|
|
|
}
|
|
|
|
}
|
2017-01-11 14:34:42 +13:00
|
|
|
|
2017-06-12 15:58:58 +12:00
|
|
|
fn rewrite_single_line(
|
|
|
|
&self,
|
|
|
|
pat_expr_str: &str,
|
|
|
|
context: &RewriteContext,
|
|
|
|
width: usize,
|
|
|
|
) -> Option<String> {
|
2017-01-11 14:34:42 +13:00
|
|
|
assert!(self.allow_single_line);
|
2017-10-05 20:50:19 +09:00
|
|
|
let else_block = self.else_block?;
|
2017-01-11 14:34:42 +13:00
|
|
|
let fixed_cost = self.keyword.len() + " { } else { }".len();
|
|
|
|
|
2018-05-19 08:38:50 +09:00
|
|
|
if let ast::ExprKind::Block(ref else_node, _) = else_block.node {
|
2018-08-23 17:10:46 -04:00
|
|
|
if !is_simple_block(self.block, None, context.source_map)
|
|
|
|
|| !is_simple_block(else_node, None, context.source_map)
|
2017-09-15 12:10:58 +09:00
|
|
|
|| pat_expr_str.contains('\n')
|
2017-06-12 15:58:58 +12:00
|
|
|
{
|
2017-01-11 14:34:42 +13:00
|
|
|
return None;
|
|
|
|
}
|
|
|
|
|
2017-10-05 20:50:19 +09:00
|
|
|
let new_width = width.checked_sub(pat_expr_str.len() + fixed_cost)?;
|
2017-01-11 14:34:42 +13:00
|
|
|
let expr = &self.block.stmts[0];
|
2017-10-05 20:50:19 +09:00
|
|
|
let if_str = expr.rewrite(context, Shape::legacy(new_width, Indent::empty()))?;
|
2017-01-11 14:34:42 +13:00
|
|
|
|
2017-10-05 20:50:19 +09:00
|
|
|
let new_width = new_width.checked_sub(if_str.len())?;
|
2017-01-11 14:34:42 +13:00
|
|
|
let else_expr = &else_node.stmts[0];
|
2017-10-05 20:50:19 +09:00
|
|
|
let else_str = else_expr.rewrite(context, Shape::legacy(new_width, Indent::empty()))?;
|
2017-01-11 14:34:42 +13:00
|
|
|
|
|
|
|
if if_str.contains('\n') || else_str.contains('\n') {
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
|
2017-06-12 15:58:58 +12:00
|
|
|
let result = format!(
|
|
|
|
"{} {} {{ {} }} else {{ {} }}",
|
2017-12-01 13:30:21 +09:00
|
|
|
self.keyword, pat_expr_str, if_str, else_str
|
2017-06-12 15:58:58 +12:00
|
|
|
);
|
2017-01-11 14:34:42 +13:00
|
|
|
|
|
|
|
if result.len() <= width {
|
|
|
|
return Some(result);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
None
|
|
|
|
}
|
2015-07-20 23:29:25 +02:00
|
|
|
}
|
|
|
|
|
2017-06-15 23:26:32 +09:00
|
|
|
impl<'a> ControlFlow<'a> {
|
2018-03-06 20:02:04 +09:00
|
|
|
fn rewrite_pat_expr(
|
|
|
|
&self,
|
|
|
|
context: &RewriteContext,
|
|
|
|
expr: &ast::Expr,
|
|
|
|
shape: Shape,
|
|
|
|
offset: usize,
|
|
|
|
) -> Option<String> {
|
|
|
|
debug!("rewrite_pat_expr {:?} {:?} {:?}", shape, self.pats, expr);
|
|
|
|
|
|
|
|
let cond_shape = shape.offset_left(offset)?;
|
2018-03-08 12:56:28 +09:00
|
|
|
if !self.pats.is_empty() {
|
2018-03-06 20:02:04 +09:00
|
|
|
let matcher = if self.matcher.is_empty() {
|
|
|
|
self.matcher.to_owned()
|
|
|
|
} else {
|
|
|
|
format!("{} ", self.matcher)
|
|
|
|
};
|
|
|
|
let pat_shape = cond_shape
|
|
|
|
.offset_left(matcher.len())?
|
|
|
|
.sub_width(self.connector.len())?;
|
2018-03-08 12:56:28 +09:00
|
|
|
let pat_string = rewrite_multiple_patterns(context, &self.pats, pat_shape)?;
|
2018-03-06 20:02:04 +09:00
|
|
|
let result = format!("{}{}{}", matcher, pat_string, self.connector);
|
|
|
|
return rewrite_assign_rhs(context, result, expr, cond_shape);
|
|
|
|
}
|
|
|
|
|
|
|
|
let expr_rw = expr.rewrite(context, cond_shape);
|
|
|
|
// The expression may (partially) fit on the current line.
|
|
|
|
// We do not allow splitting between `if` and condition.
|
|
|
|
if self.keyword == "if" || expr_rw.is_some() {
|
|
|
|
return expr_rw;
|
|
|
|
}
|
|
|
|
|
|
|
|
// The expression won't fit on the current line, jump to next.
|
|
|
|
let nested_shape = shape
|
|
|
|
.block_indent(context.config.tab_spaces())
|
|
|
|
.with_max_width(context.config);
|
|
|
|
let nested_indent_str = nested_shape.indent.to_string_with_newline(context.config);
|
|
|
|
expr.rewrite(context, nested_shape)
|
|
|
|
.map(|expr_rw| format!("{}{}", nested_indent_str, expr_rw))
|
|
|
|
}
|
|
|
|
|
2017-06-15 23:26:32 +09:00
|
|
|
fn rewrite_cond(
|
|
|
|
&self,
|
|
|
|
context: &RewriteContext,
|
|
|
|
shape: Shape,
|
|
|
|
alt_block_sep: &str,
|
|
|
|
) -> Option<(String, usize)> {
|
2017-07-26 17:41:45 +09:00
|
|
|
// Do not take the rhs overhead from the upper expressions into account
|
|
|
|
// when rewriting pattern.
|
2018-03-06 20:02:04 +09:00
|
|
|
let new_width = context.budget(shape.used_width());
|
2017-07-26 17:41:45 +09:00
|
|
|
let fresh_shape = Shape {
|
|
|
|
width: new_width,
|
|
|
|
..shape
|
|
|
|
};
|
2017-02-21 14:43:43 +13:00
|
|
|
let constr_shape = if self.nested_if {
|
2017-01-11 14:34:42 +13:00
|
|
|
// We are part of an if-elseif-else chain. Our constraints are tightened.
|
|
|
|
// 7 = "} else " .len()
|
2017-10-05 20:50:19 +09:00
|
|
|
fresh_shape.offset_left(7)?
|
2017-01-11 14:34:42 +13:00
|
|
|
} else {
|
2017-07-26 17:41:45 +09:00
|
|
|
fresh_shape
|
2017-01-11 14:34:42 +13:00
|
|
|
};
|
|
|
|
|
2015-07-20 23:29:25 +02:00
|
|
|
let label_string = rewrite_label(self.label);
|
2017-01-11 14:34:42 +13:00
|
|
|
// 1 = space after keyword.
|
2017-06-14 20:37:54 +09:00
|
|
|
let offset = self.keyword.len() + label_string.len() + 1;
|
2015-07-20 23:29:25 +02:00
|
|
|
|
|
|
|
let pat_expr_string = match self.cond {
|
2018-03-06 20:02:04 +09:00
|
|
|
Some(cond) => self.rewrite_pat_expr(context, cond, constr_shape, offset)?,
|
2015-08-16 15:58:17 +12:00
|
|
|
None => String::new(),
|
2015-07-20 23:29:25 +02:00
|
|
|
};
|
|
|
|
|
2017-07-26 16:28:55 +09:00
|
|
|
let brace_overhead =
|
|
|
|
if context.config.control_brace_style() != ControlBraceStyle::AlwaysNextLine {
|
|
|
|
// 2 = ` {`
|
|
|
|
2
|
|
|
|
} else {
|
|
|
|
0
|
|
|
|
};
|
|
|
|
let one_line_budget = context
|
|
|
|
.config
|
|
|
|
.max_width()
|
2018-05-14 21:58:57 +09:00
|
|
|
.saturating_sub(constr_shape.used_width() + offset + brace_overhead);
|
2017-12-10 23:54:34 +09:00
|
|
|
let force_newline_brace = (pat_expr_string.contains('\n')
|
|
|
|
|| pat_expr_string.len() > one_line_budget)
|
2017-09-15 12:10:58 +09:00
|
|
|
&& !last_line_extendable(&pat_expr_string);
|
2017-05-05 14:29:18 +12:00
|
|
|
|
2017-01-11 14:34:42 +13:00
|
|
|
// Try to format if-else on single line.
|
2017-11-24 20:17:06 +13:00
|
|
|
if self.allow_single_line
|
|
|
|
&& context
|
|
|
|
.config
|
|
|
|
.width_heuristics()
|
2018-07-06 11:58:22 +12:00
|
|
|
.single_line_if_else_max_width
|
|
|
|
> 0
|
2017-11-24 20:17:06 +13:00
|
|
|
{
|
2017-01-31 08:28:48 +13:00
|
|
|
let trial = self.rewrite_single_line(&pat_expr_string, context, shape.width);
|
2016-06-09 00:43:08 +09:00
|
|
|
|
2017-06-15 23:26:32 +09:00
|
|
|
if let Some(cond_str) = trial {
|
2018-07-06 11:58:22 +12:00
|
|
|
if cond_str.len() <= context
|
|
|
|
.config
|
|
|
|
.width_heuristics()
|
|
|
|
.single_line_if_else_max_width
|
2017-11-24 20:17:06 +13:00
|
|
|
{
|
2017-06-15 23:26:32 +09:00
|
|
|
return Some((cond_str, 0));
|
|
|
|
}
|
2017-01-11 14:34:42 +13:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let cond_span = if let Some(cond) = self.cond {
|
|
|
|
cond.span
|
|
|
|
} else {
|
2017-08-19 21:47:40 +03:00
|
|
|
mk_sp(self.block.span.lo(), self.block.span.lo())
|
2017-01-11 14:34:42 +13:00
|
|
|
};
|
|
|
|
|
2017-08-28 00:13:42 +09:00
|
|
|
// `for event in event`
|
|
|
|
// Do not include label in the span.
|
2018-05-08 06:25:48 +09:00
|
|
|
let lo = self
|
|
|
|
.label
|
2018-04-08 22:18:18 +08:00
|
|
|
.map_or(self.span.lo(), |label| label.ident.span.hi());
|
2017-06-01 12:08:09 +09:00
|
|
|
let between_kwd_cond = mk_sp(
|
2017-08-28 00:13:42 +09:00
|
|
|
context
|
2018-02-19 12:41:43 +09:00
|
|
|
.snippet_provider
|
2017-08-31 14:11:52 +12:00
|
|
|
.span_after(mk_sp(lo, self.span.hi()), self.keyword.trim()),
|
2018-03-08 12:56:28 +09:00
|
|
|
if self.pats.is_empty() {
|
|
|
|
cond_span.lo()
|
2018-03-08 16:29:00 +09:00
|
|
|
} else if self.matcher.is_empty() {
|
|
|
|
self.pats[0].span.lo()
|
2018-03-08 12:56:28 +09:00
|
|
|
} else {
|
2018-03-08 16:29:00 +09:00
|
|
|
context
|
|
|
|
.snippet_provider
|
|
|
|
.span_before(self.span, self.matcher.trim())
|
2018-03-08 12:56:28 +09:00
|
|
|
},
|
2017-06-01 12:08:09 +09:00
|
|
|
);
|
2017-01-11 14:34:42 +13:00
|
|
|
|
2017-01-31 08:28:48 +13:00
|
|
|
let between_kwd_cond_comment = extract_comment(between_kwd_cond, context, shape);
|
2017-01-11 14:34:42 +13:00
|
|
|
|
2017-01-31 08:28:48 +13:00
|
|
|
let after_cond_comment =
|
2017-08-19 21:47:40 +03:00
|
|
|
extract_comment(mk_sp(cond_span.hi(), self.block.span.lo()), context, shape);
|
2017-01-11 14:34:42 +13:00
|
|
|
|
|
|
|
let block_sep = if self.cond.is_none() && between_kwd_cond_comment.is_some() {
|
|
|
|
""
|
2017-09-15 12:10:58 +09:00
|
|
|
} else if context.config.control_brace_style() == ControlBraceStyle::AlwaysNextLine
|
|
|
|
|| force_newline_brace
|
2017-06-12 15:58:58 +12:00
|
|
|
{
|
2017-06-15 23:26:32 +09:00
|
|
|
alt_block_sep
|
2017-01-11 14:34:42 +13:00
|
|
|
} else {
|
|
|
|
" "
|
|
|
|
};
|
|
|
|
|
2017-06-15 23:26:32 +09:00
|
|
|
let used_width = if pat_expr_string.contains('\n') {
|
|
|
|
last_line_width(&pat_expr_string)
|
|
|
|
} else {
|
|
|
|
// 2 = spaces after keyword and condition.
|
|
|
|
label_string.len() + self.keyword.len() + pat_expr_string.len() + 2
|
|
|
|
};
|
|
|
|
|
|
|
|
Some((
|
|
|
|
format!(
|
|
|
|
"{}{}{}{}{}",
|
|
|
|
label_string,
|
|
|
|
self.keyword,
|
|
|
|
between_kwd_cond_comment.as_ref().map_or(
|
2017-07-06 01:03:07 +09:00
|
|
|
if pat_expr_string.is_empty() || pat_expr_string.starts_with('\n') {
|
2017-06-15 23:26:32 +09:00
|
|
|
""
|
|
|
|
} else {
|
|
|
|
" "
|
|
|
|
},
|
|
|
|
|s| &**s,
|
|
|
|
),
|
|
|
|
pat_expr_string,
|
|
|
|
after_cond_comment.as_ref().map_or(block_sep, |s| &**s)
|
|
|
|
),
|
|
|
|
used_width,
|
|
|
|
))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> Rewrite for ControlFlow<'a> {
|
|
|
|
fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
|
|
|
|
debug!("ControlFlow::rewrite {:?} {:?}", self, shape);
|
|
|
|
|
2018-02-19 12:47:54 +09:00
|
|
|
let alt_block_sep = &shape.indent.to_string_with_newline(context.config);
|
2018-02-23 09:07:35 +09:00
|
|
|
let (cond_str, used_width) = self.rewrite_cond(context, shape, alt_block_sep)?;
|
2017-06-15 23:26:32 +09:00
|
|
|
// If `used_width` is 0, it indicates that whole control flow is written in a single line.
|
|
|
|
if used_width == 0 {
|
|
|
|
return Some(cond_str);
|
|
|
|
}
|
|
|
|
|
2018-05-14 21:58:57 +09:00
|
|
|
let block_width = shape.width.saturating_sub(used_width);
|
2017-06-15 23:26:32 +09:00
|
|
|
// 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 {
|
|
|
|
min(1, block_width)
|
|
|
|
} else {
|
|
|
|
block_width
|
|
|
|
};
|
|
|
|
let block_shape = Shape {
|
|
|
|
width: block_width,
|
|
|
|
..shape
|
|
|
|
};
|
2018-03-25 20:20:50 +09:00
|
|
|
let block_str = {
|
|
|
|
let old_val = context.is_if_else_block.replace(self.else_block.is_some());
|
|
|
|
let result =
|
2018-06-07 11:15:59 +08:00
|
|
|
rewrite_block_with_visitor(context, "", self.block, None, None, block_shape, true);
|
2018-03-25 20:20:50 +09:00
|
|
|
context.is_if_else_block.replace(old_val);
|
|
|
|
result?
|
|
|
|
};
|
2017-06-15 23:26:32 +09:00
|
|
|
|
|
|
|
let mut result = format!("{}{}", cond_str, block_str);
|
2017-01-11 14:34:42 +13:00
|
|
|
|
|
|
|
if let Some(else_block) = self.else_block {
|
2017-05-13 21:07:36 +09:00
|
|
|
let shape = Shape::indented(shape.indent, context.config);
|
2017-01-11 14:34:42 +13:00
|
|
|
let mut last_in_chain = false;
|
|
|
|
let rewrite = match else_block.node {
|
|
|
|
// If the else expression is another if-else expression, prevent it
|
|
|
|
// from being formatted on a single line.
|
2017-01-31 08:28:48 +13:00
|
|
|
// Note how we're passing the original shape, as the
|
2017-01-11 14:34:42 +13:00
|
|
|
// cost of "else" should not cascade.
|
|
|
|
ast::ExprKind::IfLet(ref pat, ref cond, ref if_block, ref next_else_block) => {
|
2017-06-12 15:58:58 +12:00
|
|
|
ControlFlow::new_if(
|
|
|
|
cond,
|
2018-03-08 12:56:28 +09:00
|
|
|
ptr_vec_to_ref_vec(pat),
|
2017-06-12 15:58:58 +12:00
|
|
|
if_block,
|
|
|
|
next_else_block.as_ref().map(|e| &**e),
|
|
|
|
false,
|
|
|
|
true,
|
2017-08-19 21:47:40 +03:00
|
|
|
mk_sp(else_block.span.lo(), self.span.hi()),
|
2017-06-12 15:58:58 +12:00
|
|
|
).rewrite(context, shape)
|
2017-01-11 14:34:42 +13:00
|
|
|
}
|
|
|
|
ast::ExprKind::If(ref cond, ref if_block, ref next_else_block) => {
|
2017-06-12 15:58:58 +12:00
|
|
|
ControlFlow::new_if(
|
|
|
|
cond,
|
2018-03-08 12:56:28 +09:00
|
|
|
vec![],
|
2017-06-12 15:58:58 +12:00
|
|
|
if_block,
|
|
|
|
next_else_block.as_ref().map(|e| &**e),
|
|
|
|
false,
|
|
|
|
true,
|
2017-08-19 21:47:40 +03:00
|
|
|
mk_sp(else_block.span.lo(), self.span.hi()),
|
2017-06-12 15:58:58 +12:00
|
|
|
).rewrite(context, shape)
|
2017-01-11 14:34:42 +13:00
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
last_in_chain = true;
|
2017-01-16 16:37:58 +13:00
|
|
|
// When rewriting a block, the width is only used for single line
|
|
|
|
// blocks, passing 1 lets us avoid that.
|
2017-03-22 09:05:50 +13:00
|
|
|
let else_shape = Shape {
|
|
|
|
width: min(1, shape.width),
|
|
|
|
..shape
|
|
|
|
};
|
2017-06-20 21:35:52 +09:00
|
|
|
format_expr(else_block, ExprType::Statement, context, else_shape)
|
2017-01-11 14:34:42 +13:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2017-06-16 18:56:32 +09:00
|
|
|
let between_kwd_else_block = mk_sp(
|
2017-08-19 21:47:40 +03:00
|
|
|
self.block.span.hi(),
|
2017-06-17 16:56:54 +09:00
|
|
|
context
|
2018-02-19 12:41:43 +09:00
|
|
|
.snippet_provider
|
2017-08-19 21:47:40 +03:00
|
|
|
.span_before(mk_sp(self.block.span.hi(), else_block.span.lo()), "else"),
|
2017-06-16 18:56:32 +09:00
|
|
|
);
|
2017-01-11 14:34:42 +13:00
|
|
|
let between_kwd_else_block_comment =
|
2017-01-31 08:28:48 +13:00
|
|
|
extract_comment(between_kwd_else_block, context, shape);
|
2017-01-11 14:34:42 +13:00
|
|
|
|
2017-06-12 15:58:58 +12:00
|
|
|
let after_else = mk_sp(
|
2017-06-17 16:56:54 +09:00
|
|
|
context
|
2018-02-19 12:41:43 +09:00
|
|
|
.snippet_provider
|
2017-08-19 21:47:40 +03:00
|
|
|
.span_after(mk_sp(self.block.span.hi(), else_block.span.lo()), "else"),
|
|
|
|
else_block.span.lo(),
|
2017-06-12 15:58:58 +12:00
|
|
|
);
|
2017-01-31 08:28:48 +13:00
|
|
|
let after_else_comment = extract_comment(after_else, context, shape);
|
2017-01-11 14:34:42 +13:00
|
|
|
|
2017-05-16 15:47:09 +07:00
|
|
|
let between_sep = match context.config.control_brace_style() {
|
2017-07-10 02:24:59 +09:00
|
|
|
ControlBraceStyle::AlwaysNextLine | ControlBraceStyle::ClosingNextLine => {
|
|
|
|
&*alt_block_sep
|
|
|
|
}
|
2017-01-11 14:34:42 +13:00
|
|
|
ControlBraceStyle::AlwaysSameLine => " ",
|
|
|
|
};
|
2017-05-16 15:47:09 +07:00
|
|
|
let after_sep = match context.config.control_brace_style() {
|
2017-01-11 14:34:42 +13:00
|
|
|
ControlBraceStyle::AlwaysNextLine if last_in_chain => &*alt_block_sep,
|
|
|
|
_ => " ",
|
|
|
|
};
|
2017-10-05 21:05:28 +09:00
|
|
|
|
|
|
|
result.push_str(&format!(
|
2017-10-05 20:50:19 +09:00
|
|
|
"{}else{}",
|
|
|
|
between_kwd_else_block_comment
|
|
|
|
.as_ref()
|
|
|
|
.map_or(between_sep, |s| &**s),
|
2017-10-05 21:05:28 +09:00
|
|
|
after_else_comment.as_ref().map_or(after_sep, |s| &**s),
|
|
|
|
));
|
2017-10-05 20:50:19 +09:00
|
|
|
result.push_str(&rewrite?);
|
2017-01-11 14:34:42 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
Some(result)
|
2015-07-20 23:29:25 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-29 21:44:26 +09:00
|
|
|
fn rewrite_label(opt_label: Option<ast::Label>) -> Cow<'static, str> {
|
|
|
|
match opt_label {
|
|
|
|
Some(label) => Cow::from(format!("{}: ", label.ident)),
|
2017-09-15 18:11:24 +09:00
|
|
|
None => Cow::from(""),
|
2015-07-16 16:29:28 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-31 08:28:48 +13:00
|
|
|
fn extract_comment(span: Span, context: &RewriteContext, shape: Shape) -> Option<String> {
|
2017-08-28 00:13:42 +09:00
|
|
|
match rewrite_missing_comment(span, shape, context) {
|
|
|
|
Some(ref comment) if !comment.is_empty() => Some(format!(
|
2018-02-19 12:47:54 +09:00
|
|
|
"{indent}{}{indent}",
|
2017-06-12 15:58:58 +12:00
|
|
|
comment,
|
2018-02-19 12:47:54 +09:00
|
|
|
indent = shape.indent.to_string_with_newline(context.config)
|
2017-08-28 00:13:42 +09:00
|
|
|
)),
|
|
|
|
_ => None,
|
2016-01-12 01:09:08 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-23 17:10:46 -04:00
|
|
|
pub fn block_contains_comment(block: &ast::Block, source_map: &SourceMap) -> bool {
|
|
|
|
let snippet = source_map.span_to_snippet(block.span).unwrap();
|
2015-11-19 20:11:32 -06:00
|
|
|
contains_comment(&snippet)
|
|
|
|
}
|
2015-08-25 21:46:58 +02:00
|
|
|
|
2017-10-20 22:09:45 -07:00
|
|
|
// Checks that a block contains no statements, an expression and no comments or
|
|
|
|
// attributes.
|
2015-11-20 21:05:10 +01:00
|
|
|
// FIXME: incorrectly returns false when comment is contained completely within
|
|
|
|
// the expression.
|
2017-10-20 22:09:45 -07:00
|
|
|
pub fn is_simple_block(
|
|
|
|
block: &ast::Block,
|
|
|
|
attrs: Option<&[ast::Attribute]>,
|
2018-08-23 17:10:46 -04:00
|
|
|
source_map: &SourceMap,
|
2017-10-20 22:09:45 -07:00
|
|
|
) -> bool {
|
2018-05-06 15:22:29 +09:00
|
|
|
(block.stmts.len() == 1
|
|
|
|
&& stmt_is_expr(&block.stmts[0])
|
2018-08-23 17:10:46 -04:00
|
|
|
&& !block_contains_comment(block, source_map)
|
2018-05-06 15:22:29 +09:00
|
|
|
&& attrs.map_or(true, |a| a.is_empty()))
|
2015-08-25 21:46:58 +02:00
|
|
|
}
|
|
|
|
|
2017-10-20 22:09:45 -07:00
|
|
|
/// Checks whether a block contains at most one statement or expression, and no
|
|
|
|
/// comments or attributes.
|
|
|
|
pub fn is_simple_block_stmt(
|
|
|
|
block: &ast::Block,
|
|
|
|
attrs: Option<&[ast::Attribute]>,
|
2018-08-23 17:10:46 -04:00
|
|
|
source_map: &SourceMap,
|
2017-10-20 22:09:45 -07:00
|
|
|
) -> bool {
|
2018-05-06 15:22:29 +09:00
|
|
|
block.stmts.len() <= 1
|
2018-08-23 17:10:46 -04:00
|
|
|
&& !block_contains_comment(block, source_map)
|
2017-10-20 22:09:45 -07:00
|
|
|
&& attrs.map_or(true, |a| a.is_empty())
|
2015-11-19 01:53:25 -06:00
|
|
|
}
|
|
|
|
|
2017-10-20 22:09:45 -07:00
|
|
|
/// Checks whether a block contains no statements, expressions, comments, or
|
|
|
|
/// inner attributes.
|
|
|
|
pub fn is_empty_block(
|
|
|
|
block: &ast::Block,
|
|
|
|
attrs: Option<&[ast::Attribute]>,
|
2018-08-23 17:10:46 -04:00
|
|
|
source_map: &SourceMap,
|
2017-10-20 22:09:45 -07:00
|
|
|
) -> bool {
|
2018-05-06 15:22:29 +09:00
|
|
|
block.stmts.is_empty()
|
2018-08-23 17:10:46 -04:00
|
|
|
&& !block_contains_comment(block, source_map)
|
2017-10-20 22:09:45 -07:00
|
|
|
&& attrs.map_or(true, |a| inner_attributes(a).is_empty())
|
2016-09-16 15:19:18 +12:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn stmt_is_expr(stmt: &ast::Stmt) -> bool {
|
|
|
|
match stmt.node {
|
|
|
|
ast::StmtKind::Expr(..) => true,
|
|
|
|
_ => false,
|
|
|
|
}
|
2015-11-19 01:53:25 -06:00
|
|
|
}
|
|
|
|
|
2017-11-13 15:26:33 +13:00
|
|
|
pub fn is_unsafe_block(block: &ast::Block) -> bool {
|
2016-03-01 17:27:19 -05:00
|
|
|
if let ast::BlockCheckMode::Unsafe(..) = block.rules {
|
2015-11-14 21:57:31 +01:00
|
|
|
true
|
|
|
|
} else {
|
|
|
|
false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-21 22:02:18 +09:00
|
|
|
pub fn rewrite_multiple_patterns(
|
2017-06-12 15:58:58 +12:00
|
|
|
context: &RewriteContext,
|
2018-03-06 20:02:04 +09:00
|
|
|
pats: &[&ast::Pat],
|
2017-06-12 15:58:58 +12:00
|
|
|
shape: Shape,
|
|
|
|
) -> Option<String> {
|
2018-05-08 06:25:48 +09:00
|
|
|
let pat_strs = pats
|
|
|
|
.iter()
|
2018-03-06 20:02:04 +09:00
|
|
|
.map(|p| p.rewrite(context, shape))
|
|
|
|
.collect::<Option<Vec<_>>>()?;
|
2017-06-03 22:44:21 +09:00
|
|
|
|
2018-05-08 06:25:48 +09:00
|
|
|
let use_mixed_layout = pats
|
|
|
|
.iter()
|
2018-03-06 20:02:04 +09:00
|
|
|
.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();
|
|
|
|
let tactic = if use_mixed_layout {
|
|
|
|
DefinitiveListTactic::Mixed
|
|
|
|
} else {
|
|
|
|
definitive_tactic(
|
|
|
|
&items,
|
|
|
|
ListTactic::HorizontalVertical,
|
|
|
|
Separator::VerticalBar,
|
|
|
|
shape.width,
|
|
|
|
)
|
|
|
|
};
|
2018-08-03 22:13:20 +09:00
|
|
|
let fmt = ListFormatting::new(shape, context.config)
|
|
|
|
.tactic(tactic)
|
|
|
|
.separator(" |")
|
|
|
|
.separator_place(context.config.binop_separator())
|
|
|
|
.ends_with_newline(false);
|
2018-03-06 20:02:04 +09:00
|
|
|
write_list(&items, &fmt)
|
2015-07-19 23:42:54 +02:00
|
|
|
}
|
|
|
|
|
2017-09-28 10:47:01 +09:00
|
|
|
pub fn rewrite_literal(context: &RewriteContext, l: &ast::Lit, shape: Shape) -> Option<String> {
|
|
|
|
match l.node {
|
|
|
|
ast::LitKind::Str(_, ast::StrStyle::Cooked) => rewrite_string_lit(context, l.span, shape),
|
2017-12-06 22:52:43 +09:00
|
|
|
_ => wrap_str(
|
2017-12-08 13:07:42 +09:00
|
|
|
context.snippet(l.span).to_owned(),
|
2017-12-06 22:52:43 +09:00
|
|
|
context.config.max_width(),
|
|
|
|
shape,
|
|
|
|
),
|
2017-09-28 10:47:01 +09:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-31 08:28:48 +13:00
|
|
|
fn rewrite_string_lit(context: &RewriteContext, span: Span, shape: Shape) -> Option<String> {
|
2016-01-28 19:14:08 +13:00
|
|
|
let string_lit = context.snippet(span);
|
|
|
|
|
2017-11-24 14:07:37 +13:00
|
|
|
if !context.config.format_strings() {
|
2017-06-18 22:44:56 +09:00
|
|
|
if string_lit
|
|
|
|
.lines()
|
|
|
|
.rev()
|
|
|
|
.skip(1)
|
|
|
|
.all(|line| line.ends_with('\\'))
|
|
|
|
{
|
|
|
|
let new_indent = shape.visual_indent(1).indent;
|
2017-11-11 23:15:33 +09:00
|
|
|
let indented_string_lit = String::from(
|
2017-06-18 22:44:56 +09:00
|
|
|
string_lit
|
|
|
|
.lines()
|
|
|
|
.map(|line| {
|
2017-09-15 18:11:24 +09:00
|
|
|
format!(
|
|
|
|
"{}{}",
|
|
|
|
new_indent.to_string(context.config),
|
|
|
|
line.trim_left()
|
|
|
|
)
|
2018-07-11 21:35:10 +12:00
|
|
|
}).collect::<Vec<_>>()
|
2017-06-18 22:44:56 +09:00
|
|
|
.join("\n")
|
|
|
|
.trim_left(),
|
2017-11-11 23:15:33 +09:00
|
|
|
);
|
|
|
|
return wrap_str(indented_string_lit, context.config.max_width(), shape);
|
2017-06-18 22:44:56 +09:00
|
|
|
} else {
|
2017-12-08 13:07:42 +09:00
|
|
|
return wrap_str(string_lit.to_owned(), context.config.max_width(), shape);
|
2017-06-18 22:44:56 +09:00
|
|
|
}
|
2016-01-28 19:14:08 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
// Remove the quote characters.
|
|
|
|
let str_lit = &string_lit[1..string_lit.len() - 1];
|
2015-09-03 23:38:12 -04:00
|
|
|
|
2017-10-31 15:04:50 +09:00
|
|
|
rewrite_string(
|
|
|
|
str_lit,
|
|
|
|
&StringFormat::new(shape.visual_indent(0), context.config),
|
|
|
|
)
|
2015-06-16 17:29:05 +02:00
|
|
|
}
|
|
|
|
|
2018-03-07 15:40:52 +09:00
|
|
|
/// In case special-case style is required, returns an offset from which we start horizontal layout.
|
|
|
|
pub fn maybe_get_args_offset<T: ToExpr>(callee_str: &str, args: &[&T]) -> Option<(bool, usize)> {
|
|
|
|
if let Some(&(_, num_args_before)) = SPECIAL_MACRO_WHITELIST
|
|
|
|
.iter()
|
|
|
|
.find(|&&(s, _)| s == callee_str)
|
|
|
|
{
|
|
|
|
let all_simple = args.len() > num_args_before && is_every_expr_simple(args);
|
|
|
|
|
|
|
|
Some((all_simple, num_args_before))
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-24 12:27:07 +00:00
|
|
|
/// A list of `format!`-like macros, that take a long format string and a list of arguments to
|
|
|
|
/// format.
|
|
|
|
///
|
|
|
|
/// Organized as a list of `(&str, usize)` tuples, giving the name of the macro and the number of
|
|
|
|
/// arguments before the format string (none for `format!("format", ...)`, one for `assert!(result,
|
|
|
|
/// "format", ...)`, two for `assert_eq!(left, right, "format", ...)`).
|
2017-12-23 01:06:17 +00:00
|
|
|
const SPECIAL_MACRO_WHITELIST: &[(&str, usize)] = &[
|
|
|
|
// format! like macros
|
2017-12-03 11:37:55 +09:00
|
|
|
// From the Rust Standard Library.
|
2017-12-23 01:06:17 +00:00
|
|
|
("eprint!", 0),
|
|
|
|
("eprintln!", 0),
|
|
|
|
("format!", 0),
|
|
|
|
("format_args!", 0),
|
|
|
|
("print!", 0),
|
|
|
|
("println!", 0),
|
|
|
|
("panic!", 0),
|
|
|
|
("unreachable!", 0),
|
2017-12-03 11:37:55 +09:00
|
|
|
// From the `log` crate.
|
2017-12-23 01:06:17 +00:00
|
|
|
("debug!", 0),
|
|
|
|
("error!", 0),
|
|
|
|
("info!", 0),
|
|
|
|
("warn!", 0),
|
|
|
|
// write! like macros
|
|
|
|
("assert!", 1),
|
|
|
|
("debug_assert!", 1),
|
|
|
|
("write!", 1),
|
|
|
|
("writeln!", 1),
|
|
|
|
// assert_eq! like macros
|
|
|
|
("assert_eq!", 2),
|
|
|
|
("assert_ne!", 2),
|
|
|
|
("debug_assert_eq!", 2),
|
|
|
|
("debug_assert_ne!", 2),
|
2017-12-01 13:28:36 +09:00
|
|
|
];
|
|
|
|
|
2018-04-28 15:09:54 +09:00
|
|
|
fn choose_separator_tactic(context: &RewriteContext, span: Span) -> Option<SeparatorTactic> {
|
|
|
|
if context.inside_macro() {
|
|
|
|
if span_ends_with_comma(context, span) {
|
|
|
|
Some(SeparatorTactic::Always)
|
|
|
|
} else {
|
|
|
|
Some(SeparatorTactic::Never)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-12 15:58:58 +12:00
|
|
|
pub fn rewrite_call(
|
|
|
|
context: &RewriteContext,
|
|
|
|
callee: &str,
|
|
|
|
args: &[ptr::P<ast::Expr>],
|
|
|
|
span: Span,
|
|
|
|
shape: Shape,
|
|
|
|
) -> Option<String> {
|
2018-03-07 15:40:52 +09:00
|
|
|
overflow::rewrite_with_parens(
|
2017-06-15 16:25:40 +09:00
|
|
|
context,
|
2017-08-29 22:16:04 +09:00
|
|
|
callee,
|
2017-10-26 16:54:41 +09:00
|
|
|
&ptr_vec_to_ref_vec(args),
|
2017-06-15 16:25:40 +09:00
|
|
|
shape,
|
2018-03-07 15:40:52 +09:00
|
|
|
span,
|
2017-11-24 20:17:06 +13:00
|
|
|
context.config.width_heuristics().fn_call_width,
|
2018-04-28 15:09:54 +09:00
|
|
|
choose_separator_tactic(context, span),
|
2018-03-07 15:40:52 +09:00
|
|
|
)
|
2017-06-03 22:49:29 +09:00
|
|
|
}
|
2015-10-08 23:07:19 +02:00
|
|
|
|
2018-03-07 15:40:52 +09:00
|
|
|
fn is_simple_expr(expr: &ast::Expr) -> bool {
|
2017-12-01 13:30:04 +09:00
|
|
|
match expr.node {
|
|
|
|
ast::ExprKind::Lit(..) => true,
|
|
|
|
ast::ExprKind::Path(ref qself, ref path) => qself.is_none() && path.segments.len() <= 1,
|
|
|
|
ast::ExprKind::AddrOf(_, ref expr)
|
|
|
|
| ast::ExprKind::Box(ref expr)
|
|
|
|
| ast::ExprKind::Cast(ref expr, _)
|
|
|
|
| ast::ExprKind::Field(ref expr, _)
|
|
|
|
| ast::ExprKind::Try(ref expr)
|
2018-03-07 15:40:52 +09:00
|
|
|
| ast::ExprKind::Unary(_, ref expr) => is_simple_expr(expr),
|
2018-05-23 06:04:14 +09:00
|
|
|
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)
|
2017-12-01 13:30:04 +09:00
|
|
|
}
|
|
|
|
_ => false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-26 07:36:44 +09:00
|
|
|
pub fn is_every_expr_simple<T: ToExpr>(lists: &[&T]) -> bool {
|
2017-12-01 13:30:04 +09:00
|
|
|
lists
|
|
|
|
.iter()
|
2018-03-07 15:40:52 +09:00
|
|
|
.all(|arg| arg.to_expr().map_or(false, is_simple_expr))
|
2017-05-23 11:20:29 +09:00
|
|
|
}
|
|
|
|
|
2017-06-15 16:25:40 +09:00
|
|
|
pub fn can_be_overflowed_expr(context: &RewriteContext, expr: &ast::Expr, args_len: usize) -> bool {
|
2017-06-03 22:49:29 +09:00
|
|
|
match expr.node {
|
|
|
|
ast::ExprKind::Match(..) => {
|
2017-09-15 12:10:58 +09:00
|
|
|
(context.use_block_indent() && args_len == 1)
|
2017-11-13 16:42:29 +09:00
|
|
|
|| (context.config.indent_style() == IndentStyle::Visual && args_len > 1)
|
2017-06-03 22:49:29 +09:00
|
|
|
}
|
2017-11-16 16:42:07 +09:00
|
|
|
ast::ExprKind::If(..)
|
|
|
|
| ast::ExprKind::IfLet(..)
|
|
|
|
| ast::ExprKind::ForLoop(..)
|
|
|
|
| ast::ExprKind::Loop(..)
|
|
|
|
| ast::ExprKind::While(..)
|
|
|
|
| ast::ExprKind::WhileLet(..) => {
|
2017-06-03 22:50:13 +09:00
|
|
|
context.config.combine_control_expr() && context.use_block_indent() && args_len == 1
|
2017-06-03 22:49:29 +09:00
|
|
|
}
|
2017-07-10 02:24:59 +09:00
|
|
|
ast::ExprKind::Block(..) | ast::ExprKind::Closure(..) => {
|
2017-09-15 12:10:58 +09:00
|
|
|
context.use_block_indent()
|
2017-11-13 16:42:29 +09:00
|
|
|
|| context.config.indent_style() == IndentStyle::Visual && args_len > 1
|
2017-06-03 22:49:29 +09:00
|
|
|
}
|
2017-11-16 16:42:07 +09:00
|
|
|
ast::ExprKind::Array(..)
|
|
|
|
| ast::ExprKind::Call(..)
|
|
|
|
| ast::ExprKind::Mac(..)
|
|
|
|
| ast::ExprKind::MethodCall(..)
|
|
|
|
| ast::ExprKind::Struct(..)
|
|
|
|
| ast::ExprKind::Tup(..) => context.use_block_indent() && args_len == 1,
|
|
|
|
ast::ExprKind::AddrOf(_, ref expr)
|
|
|
|
| ast::ExprKind::Box(ref expr)
|
|
|
|
| ast::ExprKind::Try(ref expr)
|
|
|
|
| ast::ExprKind::Unary(_, ref expr)
|
|
|
|
| ast::ExprKind::Cast(ref expr, _) => can_be_overflowed_expr(context, expr, args_len),
|
2017-06-03 22:49:29 +09:00
|
|
|
_ => false,
|
2017-05-23 11:20:29 +09:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-07 15:40:52 +09:00
|
|
|
pub fn is_nested_call(expr: &ast::Expr) -> bool {
|
2017-11-29 17:36:51 +09:00
|
|
|
match expr.node {
|
|
|
|
ast::ExprKind::Call(..) | ast::ExprKind::Mac(..) => true,
|
|
|
|
ast::ExprKind::AddrOf(_, ref expr)
|
|
|
|
| ast::ExprKind::Box(ref expr)
|
|
|
|
| ast::ExprKind::Try(ref expr)
|
|
|
|
| ast::ExprKind::Unary(_, ref expr)
|
|
|
|
| ast::ExprKind::Cast(ref expr, _) => is_nested_call(expr),
|
|
|
|
_ => false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-27 16:41:31 +09:00
|
|
|
/// Return true if a function call or a method call represented by the given span ends with a
|
|
|
|
/// trailing comma. This function is used when rewriting macro, as adding or removing a trailing
|
|
|
|
/// comma from macro can potentially break the code.
|
2018-03-07 15:40:52 +09:00
|
|
|
pub fn span_ends_with_comma(context: &RewriteContext, span: Span) -> bool {
|
2018-03-08 17:05:39 +08:00
|
|
|
let mut result: bool = Default::default();
|
|
|
|
let mut prev_char: char = Default::default();
|
2018-04-28 15:09:54 +09:00
|
|
|
let closing_delimiters = &[')', '}', ']'];
|
2018-03-08 17:05:39 +08:00
|
|
|
|
|
|
|
for (kind, c) in CharClasses::new(context.snippet(span).chars()) {
|
2017-10-27 16:41:31 +09:00
|
|
|
match c {
|
2018-03-08 17:05:39 +08:00
|
|
|
_ if kind.is_comment() || c.is_whitespace() => continue,
|
2018-04-28 15:09:54 +09:00
|
|
|
c if closing_delimiters.contains(&c) => {
|
|
|
|
result &= !closing_delimiters.contains(&prev_char);
|
|
|
|
}
|
2018-03-08 17:05:39 +08:00
|
|
|
',' => result = true,
|
|
|
|
_ => result = false,
|
2017-10-27 16:41:31 +09:00
|
|
|
}
|
2018-03-08 17:05:39 +08:00
|
|
|
prev_char = c;
|
2017-10-27 16:41:31 +09:00
|
|
|
}
|
2018-03-08 17:05:39 +08:00
|
|
|
|
|
|
|
result
|
2017-06-23 13:40:30 +09:00
|
|
|
}
|
|
|
|
|
2018-03-08 20:25:18 +09:00
|
|
|
fn rewrite_paren(
|
|
|
|
context: &RewriteContext,
|
|
|
|
mut subexpr: &ast::Expr,
|
|
|
|
shape: Shape,
|
|
|
|
mut span: Span,
|
|
|
|
) -> Option<String> {
|
2017-01-31 08:28:48 +13:00
|
|
|
debug!("rewrite_paren, shape: {:?}", shape);
|
2018-03-08 20:25:18 +09:00
|
|
|
|
|
|
|
// Extract comments within parens.
|
|
|
|
let mut pre_comment;
|
|
|
|
let mut post_comment;
|
2018-05-05 23:13:49 +08:00
|
|
|
let remove_nested_parens = context.config.remove_nested_parens();
|
2018-03-08 20:25:18 +09:00
|
|
|
loop {
|
|
|
|
// 1 = "(" or ")"
|
|
|
|
let pre_span = mk_sp(span.lo() + BytePos(1), subexpr.span.lo());
|
|
|
|
let post_span = mk_sp(subexpr.span.hi(), span.hi() - BytePos(1));
|
|
|
|
pre_comment = rewrite_missing_comment(pre_span, shape, context)?;
|
|
|
|
post_comment = rewrite_missing_comment(post_span, shape, context)?;
|
|
|
|
|
|
|
|
// Remove nested parens if there are no comments.
|
|
|
|
if let ast::ExprKind::Paren(ref subsubexpr) = subexpr.node {
|
2018-05-05 23:13:49 +08:00
|
|
|
if remove_nested_parens && pre_comment.is_empty() && post_comment.is_empty() {
|
2018-03-08 20:25:18 +09:00
|
|
|
span = subexpr.span;
|
|
|
|
subexpr = subsubexpr;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2018-05-18 16:35:09 +12:00
|
|
|
// 1 `(`
|
|
|
|
let sub_shape = shape.offset_left(1).and_then(|s| s.sub_width(1))?;
|
2017-06-14 20:37:54 +09:00
|
|
|
|
2017-10-05 20:50:19 +09:00
|
|
|
let subexpr_str = subexpr.rewrite(context, sub_shape)?;
|
2017-06-14 20:37:54 +09:00
|
|
|
debug!("rewrite_paren, subexpr_str: `{:?}`", subexpr_str);
|
|
|
|
|
2018-05-18 16:35:09 +12:00
|
|
|
// 2 = `()`
|
|
|
|
if subexpr_str.contains('\n') || first_line_width(&subexpr_str) + 2 <= shape.width {
|
|
|
|
Some(format!("({}{}{})", pre_comment, &subexpr_str, post_comment))
|
2017-06-14 20:37:54 +09:00
|
|
|
} else {
|
2017-07-20 00:30:42 +09:00
|
|
|
None
|
2017-06-14 20:37:54 +09:00
|
|
|
}
|
2015-06-16 17:29:05 +02:00
|
|
|
}
|
2015-05-24 19:57:13 +02:00
|
|
|
|
2017-06-12 15:58:58 +12:00
|
|
|
fn rewrite_index(
|
|
|
|
expr: &ast::Expr,
|
|
|
|
index: &ast::Expr,
|
|
|
|
context: &RewriteContext,
|
|
|
|
shape: Shape,
|
|
|
|
) -> Option<String> {
|
2017-10-05 20:50:19 +09:00
|
|
|
let expr_str = expr.rewrite(context, shape)?;
|
2017-01-11 12:06:23 +13:00
|
|
|
|
2018-05-18 16:35:09 +12:00
|
|
|
let offset = last_line_width(&expr_str) + 1;
|
2017-07-10 14:23:29 +09:00
|
|
|
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)
|
2018-05-18 16:35:09 +12:00
|
|
|
.and_then(|shape| shape.sub_width(1 + rhs_overhead))
|
2017-07-10 14:23:29 +09:00
|
|
|
} else {
|
2018-05-18 16:35:09 +12:00
|
|
|
shape.visual_indent(offset).sub_width(offset + 1)
|
2017-07-10 14:23:29 +09:00
|
|
|
};
|
|
|
|
let orig_index_rw = index_shape.and_then(|s| index.rewrite(context, s));
|
2017-06-26 07:57:06 +09:00
|
|
|
|
2017-07-10 14:23:29 +09:00
|
|
|
// Return if index fits in a single line.
|
2017-06-26 07:57:06 +09:00
|
|
|
match orig_index_rw {
|
|
|
|
Some(ref index_str) if !index_str.contains('\n') => {
|
2018-05-18 16:35:09 +12:00
|
|
|
return Some(format!("{}[{}]", expr_str, index_str));
|
2017-05-25 23:01:41 +09:00
|
|
|
}
|
2017-06-26 07:57:06 +09:00
|
|
|
_ => (),
|
2017-01-11 12:06:23 +13:00
|
|
|
}
|
|
|
|
|
2017-06-26 07:57:06 +09:00
|
|
|
// Try putting index on the next line and see if it fits in a single line.
|
2017-07-10 02:16:57 +09:00
|
|
|
let indent = shape.indent.block_indent(context.config);
|
2018-05-18 16:35:09 +12:00
|
|
|
let index_shape = Shape::indented(indent, context.config).offset_left(1)?;
|
|
|
|
let index_shape = index_shape.sub_width(1 + rhs_overhead)?;
|
2017-06-26 07:57:06 +09:00
|
|
|
let new_index_rw = index.rewrite(context, index_shape);
|
|
|
|
match (orig_index_rw, new_index_rw) {
|
2017-07-11 21:53:10 +09:00
|
|
|
(_, Some(ref new_index_str)) if !new_index_str.contains('\n') => Some(format!(
|
2018-05-18 16:35:09 +12:00
|
|
|
"{}{}[{}]",
|
2017-07-11 21:53:10 +09:00
|
|
|
expr_str,
|
2018-02-19 12:47:54 +09:00
|
|
|
indent.to_string_with_newline(context.config),
|
2017-07-11 21:53:10 +09:00
|
|
|
new_index_str,
|
|
|
|
)),
|
|
|
|
(None, Some(ref new_index_str)) => Some(format!(
|
2018-05-18 16:35:09 +12:00
|
|
|
"{}{}[{}]",
|
2017-07-11 21:53:10 +09:00
|
|
|
expr_str,
|
2018-02-19 12:47:54 +09:00
|
|
|
indent.to_string_with_newline(context.config),
|
2017-07-11 21:53:10 +09:00
|
|
|
new_index_str,
|
|
|
|
)),
|
2018-05-18 16:35:09 +12:00
|
|
|
(Some(ref index_str), _) => Some(format!("{}[{}]", expr_str, index_str)),
|
2017-06-26 07:57:06 +09:00
|
|
|
_ => None,
|
|
|
|
}
|
2017-01-11 12:06:23 +13:00
|
|
|
}
|
|
|
|
|
2017-07-03 18:54:41 +09:00
|
|
|
fn struct_lit_can_be_aligned(fields: &[ast::Field], base: &Option<&ast::Expr>) -> bool {
|
|
|
|
if base.is_some() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
fields.iter().all(|field| !field.is_shorthand)
|
|
|
|
}
|
|
|
|
|
2017-06-12 15:58:58 +12:00
|
|
|
fn rewrite_struct_lit<'a>(
|
|
|
|
context: &RewriteContext,
|
|
|
|
path: &ast::Path,
|
|
|
|
fields: &'a [ast::Field],
|
|
|
|
base: Option<&'a ast::Expr>,
|
|
|
|
span: Span,
|
|
|
|
shape: Shape,
|
|
|
|
) -> Option<String> {
|
2017-01-31 08:28:48 +13:00
|
|
|
debug!("rewrite_struct_lit: shape {:?}", shape);
|
2015-05-25 19:11:53 +12:00
|
|
|
|
2015-06-24 01:11:29 +02:00
|
|
|
enum StructLitField<'a> {
|
|
|
|
Regular(&'a ast::Field),
|
2015-07-03 11:13:28 +02:00
|
|
|
Base(&'a ast::Expr),
|
2015-06-24 01:11:29 +02:00
|
|
|
}
|
|
|
|
|
2015-08-14 14:09:19 +02:00
|
|
|
// 2 = " {".len()
|
2017-10-05 20:50:19 +09:00
|
|
|
let path_shape = shape.sub_width(2)?;
|
|
|
|
let path_str = rewrite_path(context, PathContext::Expr, None, path, path_shape)?;
|
2015-08-14 14:09:19 +02:00
|
|
|
|
2017-08-29 22:16:04 +09:00
|
|
|
if fields.is_empty() && base.is_none() {
|
2017-03-21 11:23:59 +13:00
|
|
|
return Some(format!("{} {{}}", path_str));
|
|
|
|
}
|
2015-05-25 19:11:53 +12:00
|
|
|
|
2017-03-21 11:23:59 +13:00
|
|
|
// Foo { a: Foo } - indent is +3, width is -5.
|
2017-10-05 20:50:19 +09:00
|
|
|
let (h_shape, v_shape) = struct_lit_shape(shape, context, path_str.len() + 3, 2)?;
|
2017-03-21 11:23:59 +13:00
|
|
|
|
2017-07-03 18:54:41 +09:00
|
|
|
let one_line_width = h_shape.map_or(0, |shape| shape.width);
|
2018-02-19 12:41:43 +09:00
|
|
|
let body_lo = context.snippet_provider.span_after(span, "{");
|
2017-09-15 12:10:58 +09:00
|
|
|
let fields_str = if struct_lit_can_be_aligned(fields, &base)
|
|
|
|
&& context.config.struct_field_align_threshold() > 0
|
2017-07-03 18:54:41 +09:00
|
|
|
{
|
2017-10-05 20:50:19 +09:00
|
|
|
rewrite_with_alignment(
|
2017-07-03 18:54:41 +09:00
|
|
|
fields,
|
|
|
|
context,
|
|
|
|
shape,
|
2017-08-19 21:47:40 +03:00
|
|
|
mk_sp(body_lo, span.hi()),
|
2017-07-03 18:54:41 +09:00
|
|
|
one_line_width,
|
2017-10-05 20:50:19 +09:00
|
|
|
)?
|
2017-07-03 18:54:41 +09:00
|
|
|
} else {
|
|
|
|
let field_iter = fields
|
|
|
|
.into_iter()
|
|
|
|
.map(StructLitField::Regular)
|
|
|
|
.chain(base.into_iter().map(StructLitField::Base));
|
|
|
|
|
|
|
|
let span_lo = |item: &StructLitField| match *item {
|
2017-08-19 21:47:40 +03:00
|
|
|
StructLitField::Regular(field) => field.span().lo(),
|
2017-07-03 18:54:41 +09:00
|
|
|
StructLitField::Base(expr) => {
|
2017-08-19 21:47:40 +03:00
|
|
|
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()));
|
2017-07-03 18:54:41 +09:00
|
|
|
let pos = snippet.find_uncommented("..").unwrap();
|
|
|
|
last_field_hi + BytePos(pos as u32)
|
|
|
|
}
|
|
|
|
};
|
|
|
|
let span_hi = |item: &StructLitField| match *item {
|
2017-08-19 21:47:40 +03:00
|
|
|
StructLitField::Regular(field) => field.span().hi(),
|
|
|
|
StructLitField::Base(expr) => expr.span.hi(),
|
2017-07-03 18:54:41 +09:00
|
|
|
};
|
|
|
|
let rewrite = |item: &StructLitField| match *item {
|
|
|
|
StructLitField::Regular(field) => {
|
|
|
|
// The 1 taken from the v_budget is for the comma.
|
2017-10-05 20:50:19 +09:00
|
|
|
rewrite_field(context, field, v_shape.sub_width(1)?, 0)
|
2017-07-03 18:54:41 +09:00
|
|
|
}
|
|
|
|
StructLitField::Base(expr) => {
|
|
|
|
// 2 = ..
|
2017-10-05 20:50:19 +09:00
|
|
|
expr.rewrite(context, v_shape.offset_left(2)?)
|
2017-07-03 18:54:41 +09:00
|
|
|
.map(|s| format!("..{}", s))
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
let items = itemize_list(
|
2018-02-19 12:41:43 +09:00
|
|
|
context.snippet_provider,
|
2017-07-03 18:54:41 +09:00
|
|
|
field_iter,
|
|
|
|
"}",
|
2017-11-16 17:38:12 +09:00
|
|
|
",",
|
2017-07-03 18:54:41 +09:00
|
|
|
span_lo,
|
|
|
|
span_hi,
|
|
|
|
rewrite,
|
|
|
|
body_lo,
|
2017-08-19 21:47:40 +03:00
|
|
|
span.hi(),
|
2017-08-07 17:29:55 +09:00
|
|
|
false,
|
2017-07-03 18:54:41 +09:00
|
|
|
);
|
|
|
|
let item_vec = items.collect::<Vec<_>>();
|
|
|
|
|
|
|
|
let tactic = struct_lit_tactic(h_shape, context, &item_vec);
|
|
|
|
let nested_shape = shape_for_tactic(tactic, h_shape, v_shape);
|
2018-03-08 17:05:39 +08:00
|
|
|
|
|
|
|
let ends_with_comma = span_ends_with_comma(context, span);
|
2018-04-25 07:21:23 +09:00
|
|
|
let force_no_trailing_comma = context.inside_macro() && !ends_with_comma;
|
2018-03-08 17:05:39 +08:00
|
|
|
|
|
|
|
let fmt = struct_lit_formatting(
|
|
|
|
nested_shape,
|
|
|
|
tactic,
|
|
|
|
context,
|
|
|
|
force_no_trailing_comma || base.is_some(),
|
|
|
|
);
|
2017-07-03 18:54:41 +09:00
|
|
|
|
2017-10-05 20:50:19 +09:00
|
|
|
write_list(&item_vec, &fmt)?
|
2017-03-21 11:23:59 +13:00
|
|
|
};
|
|
|
|
|
2017-07-03 18:53:47 +09:00
|
|
|
let fields_str = wrap_struct_field(context, &fields_str, shape, v_shape, one_line_width);
|
|
|
|
Some(format!("{} {{{}}}", path_str, fields_str))
|
2015-10-02 13:50:24 +02:00
|
|
|
|
2017-11-13 16:42:29 +09:00
|
|
|
// FIXME if context.config.indent_style() == Visual, but we run out
|
2017-07-03 18:53:47 +09:00
|
|
|
// of space, we should fall back to BlockIndent.
|
|
|
|
}
|
2015-06-24 01:11:29 +02:00
|
|
|
|
2017-07-03 18:53:47 +09:00
|
|
|
pub fn wrap_struct_field(
|
|
|
|
context: &RewriteContext,
|
|
|
|
fields_str: &str,
|
|
|
|
shape: Shape,
|
|
|
|
nested_shape: Shape,
|
|
|
|
one_line_width: usize,
|
|
|
|
) -> String {
|
2017-11-13 16:42:29 +09:00
|
|
|
if context.config.indent_style() == IndentStyle::Block
|
2018-05-06 15:22:29 +09:00
|
|
|
&& (fields_str.contains('\n')
|
|
|
|
|| !context.config.struct_lit_single_line()
|
2017-09-15 12:10:58 +09:00
|
|
|
|| fields_str.len() > one_line_width)
|
2017-06-12 15:58:58 +12:00
|
|
|
{
|
|
|
|
format!(
|
2018-02-19 12:47:54 +09:00
|
|
|
"{}{}{}",
|
|
|
|
nested_shape.indent.to_string_with_newline(context.config),
|
2017-06-12 15:58:58 +12:00
|
|
|
fields_str,
|
2018-02-19 12:47:54 +09:00
|
|
|
shape.indent.to_string_with_newline(context.config)
|
2017-06-12 15:58:58 +12:00
|
|
|
)
|
2017-02-21 14:43:43 +13:00
|
|
|
} else {
|
2017-03-21 11:23:59 +13:00
|
|
|
// One liner or visual indent.
|
|
|
|
format!(" {} ", fields_str)
|
2017-07-03 18:53:47 +09:00
|
|
|
}
|
2015-06-16 17:29:05 +02:00
|
|
|
}
|
2017-06-11 23:26:49 +09:00
|
|
|
|
2017-06-06 03:11:17 +02:00
|
|
|
pub fn struct_lit_field_separator(config: &Config) -> &str {
|
2017-11-14 23:25:36 +09:00
|
|
|
colon_spaces(config.space_before_colon(), config.space_after_colon())
|
2016-08-04 00:17:47 -04:00
|
|
|
}
|
|
|
|
|
2017-07-03 18:54:41 +09:00
|
|
|
pub fn rewrite_field(
|
|
|
|
context: &RewriteContext,
|
|
|
|
field: &ast::Field,
|
|
|
|
shape: Shape,
|
|
|
|
prefix_max_width: usize,
|
|
|
|
) -> Option<String> {
|
|
|
|
if contains_skip(&field.attrs) {
|
2017-12-08 13:07:42 +09:00
|
|
|
return Some(context.snippet(field.span()).to_owned());
|
2017-07-03 18:54:41 +09:00
|
|
|
}
|
2018-01-22 13:04:20 +09:00
|
|
|
let mut attrs_str = field.attrs.rewrite(context, shape)?;
|
|
|
|
if !attrs_str.is_empty() {
|
2018-02-19 12:47:54 +09:00
|
|
|
attrs_str.push_str(&shape.indent.to_string_with_newline(context.config));
|
2018-01-22 13:04:20 +09:00
|
|
|
};
|
2018-07-28 19:38:14 -07:00
|
|
|
let name = context.snippet(field.ident.span);
|
2017-02-13 03:16:11 +09:00
|
|
|
if field.is_shorthand {
|
2018-01-22 13:04:20 +09:00
|
|
|
Some(attrs_str + &name)
|
2017-02-13 03:16:11 +09:00
|
|
|
} else {
|
2017-07-03 18:54:41 +09:00
|
|
|
let mut separator = String::from(struct_lit_field_separator(context.config));
|
2018-05-14 21:58:57 +09:00
|
|
|
for _ in 0..prefix_max_width.saturating_sub(name.len()) {
|
2017-07-03 18:54:41 +09:00
|
|
|
separator.push(' ');
|
|
|
|
}
|
2017-02-13 03:16:11 +09:00
|
|
|
let overhead = name.len() + separator.len();
|
2017-10-05 20:50:19 +09:00
|
|
|
let expr_shape = shape.offset_left(overhead)?;
|
2017-02-21 14:43:43 +13:00
|
|
|
let expr = field.expr.rewrite(context, expr_shape);
|
2017-02-13 03:16:11 +09:00
|
|
|
|
|
|
|
match expr {
|
2018-01-29 22:14:25 +09:00
|
|
|
Some(ref e) if e.as_str() == name && context.config.use_field_init_shorthand() => {
|
|
|
|
Some(attrs_str + &name)
|
|
|
|
}
|
2017-05-12 17:58:38 +09:00
|
|
|
Some(e) => Some(format!("{}{}{}{}", attrs_str, name, separator, e)),
|
2017-02-13 03:16:11 +09:00
|
|
|
None => {
|
|
|
|
let expr_offset = shape.indent.block_indent(context.config);
|
2017-06-17 16:56:54 +09:00
|
|
|
let expr = field
|
|
|
|
.expr
|
|
|
|
.rewrite(context, Shape::indented(expr_offset, context.config));
|
2017-05-12 17:58:38 +09:00
|
|
|
expr.map(|s| {
|
2017-06-12 15:58:58 +12:00
|
|
|
format!(
|
|
|
|
"{}{}:\n{}{}",
|
|
|
|
attrs_str,
|
|
|
|
name,
|
2017-08-29 22:16:04 +09:00
|
|
|
expr_offset.to_string(context.config),
|
2017-06-12 15:58:58 +12:00
|
|
|
s
|
|
|
|
)
|
|
|
|
})
|
2017-02-13 03:16:11 +09:00
|
|
|
}
|
2016-01-14 20:26:15 +13:00
|
|
|
}
|
|
|
|
}
|
2015-06-16 17:29:05 +02:00
|
|
|
}
|
2015-05-25 19:11:53 +12:00
|
|
|
|
2017-06-14 09:29:39 +09:00
|
|
|
fn rewrite_tuple_in_visual_indent_style<'a, T>(
|
2017-06-12 15:58:58 +12:00
|
|
|
context: &RewriteContext,
|
2017-06-15 16:25:40 +09:00
|
|
|
items: &[&T],
|
2017-06-12 15:58:58 +12:00
|
|
|
span: Span,
|
|
|
|
shape: Shape,
|
|
|
|
) -> Option<String>
|
|
|
|
where
|
2017-06-14 09:29:39 +09:00
|
|
|
T: Rewrite + Spanned + ToExpr + 'a,
|
2015-10-17 15:56:53 +02:00
|
|
|
{
|
2017-06-14 09:29:39 +09:00
|
|
|
let mut items = items.iter();
|
2015-07-15 00:38:54 +02:00
|
|
|
// In case of length 1, need a trailing comma
|
2017-06-14 09:29:39 +09:00
|
|
|
debug!("rewrite_tuple_in_visual_indent_style {:?}", shape);
|
2015-07-15 00:38:54 +02:00
|
|
|
if items.len() == 1 {
|
|
|
|
// 3 = "(" + ",)"
|
2017-10-05 20:50:19 +09:00
|
|
|
let nested_shape = shape.sub_width(3)?.visual_indent(1);
|
2017-11-02 21:45:00 +09:00
|
|
|
return items
|
|
|
|
.next()
|
|
|
|
.unwrap()
|
|
|
|
.rewrite(context, nested_shape)
|
2018-05-18 16:35:09 +12:00
|
|
|
.map(|s| format!("({},)", s));
|
2015-07-15 00:38:54 +02:00
|
|
|
}
|
2015-06-23 15:58:58 +02:00
|
|
|
|
2018-02-19 12:41:43 +09:00
|
|
|
let list_lo = context.snippet_provider.span_after(span, "(");
|
2017-10-05 20:50:19 +09:00
|
|
|
let nested_shape = shape.sub_width(2)?.visual_indent(1);
|
2017-06-12 15:58:58 +12:00
|
|
|
let items = itemize_list(
|
2018-02-19 12:41:43 +09:00
|
|
|
context.snippet_provider,
|
2017-06-12 15:58:58 +12:00
|
|
|
items,
|
|
|
|
")",
|
2017-11-16 17:38:12 +09:00
|
|
|
",",
|
2017-08-19 21:47:40 +03:00
|
|
|
|item| item.span().lo(),
|
|
|
|
|item| item.span().hi(),
|
2017-06-12 15:58:58 +12:00
|
|
|
|item| item.rewrite(context, nested_shape),
|
|
|
|
list_lo,
|
2017-08-19 21:47:40 +03:00
|
|
|
span.hi() - BytePos(1),
|
2017-08-07 17:29:55 +09:00
|
|
|
false,
|
2017-06-12 15:58:58 +12:00
|
|
|
);
|
2017-06-24 19:46:36 +09:00
|
|
|
let item_vec: Vec<_> = items.collect();
|
|
|
|
let tactic = definitive_tactic(
|
|
|
|
&item_vec,
|
|
|
|
ListTactic::HorizontalVertical,
|
2017-07-31 16:23:42 +09:00
|
|
|
Separator::Comma,
|
2017-06-24 19:46:36 +09:00
|
|
|
nested_shape.width,
|
|
|
|
);
|
2018-08-03 22:13:20 +09:00
|
|
|
let fmt = ListFormatting::new(shape, context.config)
|
|
|
|
.tactic(tactic)
|
|
|
|
.ends_with_newline(false);
|
2017-10-05 20:50:19 +09:00
|
|
|
let list_str = write_list(&item_vec, &fmt)?;
|
2015-06-23 15:58:58 +02:00
|
|
|
|
2018-05-18 16:35:09 +12:00
|
|
|
Some(format!("({})", list_str))
|
2015-06-23 15:58:58 +02:00
|
|
|
}
|
2015-07-02 22:40:20 +02:00
|
|
|
|
2017-06-14 09:29:39 +09:00
|
|
|
pub fn rewrite_tuple<'a, T>(
|
2017-06-12 15:58:58 +12:00
|
|
|
context: &RewriteContext,
|
2017-06-15 16:25:40 +09:00
|
|
|
items: &[&T],
|
2017-06-12 15:58:58 +12:00
|
|
|
span: Span,
|
|
|
|
shape: Shape,
|
2017-06-14 09:29:39 +09:00
|
|
|
) -> Option<String>
|
|
|
|
where
|
|
|
|
T: Rewrite + Spanned + ToExpr + 'a,
|
|
|
|
{
|
2017-05-23 11:20:29 +09:00
|
|
|
debug!("rewrite_tuple {:?}", shape);
|
2017-06-14 09:29:39 +09:00
|
|
|
if context.use_block_indent() {
|
2017-08-18 17:10:50 -07:00
|
|
|
// We use the same rule as function calls for rewriting tuples.
|
2018-03-25 20:20:50 +09:00
|
|
|
let force_tactic = if context.inside_macro() {
|
2018-03-07 19:29:42 +09:00
|
|
|
if span_ends_with_comma(context, span) {
|
|
|
|
Some(SeparatorTactic::Always)
|
|
|
|
} else {
|
|
|
|
Some(SeparatorTactic::Never)
|
|
|
|
}
|
2018-04-25 07:21:23 +09:00
|
|
|
} else if items.len() == 1 {
|
|
|
|
Some(SeparatorTactic::Always)
|
2017-06-23 13:40:30 +09:00
|
|
|
} else {
|
2018-04-25 07:21:23 +09:00
|
|
|
None
|
2017-06-23 13:40:30 +09:00
|
|
|
};
|
2018-03-07 15:40:52 +09:00
|
|
|
overflow::rewrite_with_parens(
|
2017-06-14 09:29:39 +09:00
|
|
|
context,
|
2018-03-07 15:40:52 +09:00
|
|
|
"",
|
2017-06-14 09:29:39 +09:00
|
|
|
items,
|
|
|
|
shape,
|
2018-03-07 15:40:52 +09:00
|
|
|
span,
|
2017-11-24 20:17:06 +13:00
|
|
|
context.config.width_heuristics().fn_call_width,
|
2018-03-07 19:29:42 +09:00
|
|
|
force_tactic,
|
2017-09-28 16:33:30 +09:00
|
|
|
)
|
2017-06-14 09:29:39 +09:00
|
|
|
} else {
|
|
|
|
rewrite_tuple_in_visual_indent_style(context, items, span, shape)
|
2017-05-23 11:20:29 +09:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-12 15:58:58 +12:00
|
|
|
pub fn rewrite_unary_prefix<R: Rewrite>(
|
|
|
|
context: &RewriteContext,
|
|
|
|
prefix: &str,
|
|
|
|
rewrite: &R,
|
|
|
|
shape: Shape,
|
|
|
|
) -> Option<String> {
|
2017-03-28 11:14:47 +13:00
|
|
|
rewrite
|
2017-10-05 20:50:19 +09:00
|
|
|
.rewrite(context, shape.offset_left(prefix.len())?)
|
2017-03-28 11:14:47 +13:00
|
|
|
.map(|r| format!("{}{}", prefix, r))
|
2015-09-23 22:51:37 -07:00
|
|
|
}
|
|
|
|
|
2016-05-09 20:07:59 +02:00
|
|
|
// FIXME: this is probably not correct for multi-line Rewrites. we should
|
|
|
|
// subtract suffix.len() from the last line budget, not the first!
|
2017-06-12 15:58:58 +12:00
|
|
|
pub fn rewrite_unary_suffix<R: Rewrite>(
|
|
|
|
context: &RewriteContext,
|
|
|
|
suffix: &str,
|
|
|
|
rewrite: &R,
|
|
|
|
shape: Shape,
|
|
|
|
) -> Option<String> {
|
2017-03-28 11:14:47 +13:00
|
|
|
rewrite
|
2017-10-05 20:50:19 +09:00
|
|
|
.rewrite(context, shape.sub_width(suffix.len())?)
|
2017-03-28 11:14:47 +13:00
|
|
|
.map(|mut r| {
|
2017-06-12 15:58:58 +12:00
|
|
|
r.push_str(suffix);
|
|
|
|
r
|
|
|
|
})
|
2016-05-09 20:07:59 +02:00
|
|
|
}
|
|
|
|
|
2017-06-12 15:58:58 +12:00
|
|
|
fn rewrite_unary_op(
|
|
|
|
context: &RewriteContext,
|
|
|
|
op: &ast::UnOp,
|
|
|
|
expr: &ast::Expr,
|
|
|
|
shape: Shape,
|
|
|
|
) -> Option<String> {
|
2015-07-02 22:40:20 +02:00
|
|
|
// For some reason, an UnOp is not spanned like BinOp!
|
|
|
|
let operator_str = match *op {
|
2016-03-01 17:27:19 -05:00
|
|
|
ast::UnOp::Deref => "*",
|
|
|
|
ast::UnOp::Not => "!",
|
|
|
|
ast::UnOp::Neg => "-",
|
2015-07-02 22:40:20 +02:00
|
|
|
};
|
2017-05-15 22:55:01 +09:00
|
|
|
rewrite_unary_prefix(context, operator_str, expr, shape)
|
2015-07-02 22:40:20 +02:00
|
|
|
}
|
2015-08-21 13:31:09 +02:00
|
|
|
|
2017-06-12 15:58:58 +12:00
|
|
|
fn rewrite_assignment(
|
|
|
|
context: &RewriteContext,
|
|
|
|
lhs: &ast::Expr,
|
|
|
|
rhs: &ast::Expr,
|
|
|
|
op: Option<&ast::BinOp>,
|
|
|
|
shape: Shape,
|
|
|
|
) -> Option<String> {
|
2015-08-21 13:31:09 +02:00
|
|
|
let operator_str = match op {
|
2015-07-17 23:10:15 +02:00
|
|
|
Some(op) => context.snippet(op.span),
|
2017-12-06 22:52:43 +09:00
|
|
|
None => "=",
|
2015-08-21 13:31:09 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
// 1 = space between lhs and operator.
|
2017-10-05 20:50:19 +09:00
|
|
|
let lhs_shape = shape.sub_width(operator_str.len() + 1)?;
|
|
|
|
let lhs_str = format!("{} {}", lhs.rewrite(context, lhs_shape)?, operator_str);
|
2015-08-21 13:31:09 +02:00
|
|
|
|
2017-01-31 08:28:48 +13:00
|
|
|
rewrite_assign_rhs(context, lhs_str, rhs, shape)
|
2015-08-21 13:31:09 +02:00
|
|
|
}
|
|
|
|
|
2018-03-10 14:35:53 +09:00
|
|
|
/// Controls where to put the rhs.
|
|
|
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
|
|
|
pub enum RhsTactics {
|
|
|
|
/// Use heuristics.
|
|
|
|
Default,
|
2018-06-25 15:24:00 +09:00
|
|
|
/// Put the rhs on the next line if it uses multiple line, without extra indentation.
|
|
|
|
ForceNextLineWithoutIndent,
|
2018-03-10 14:35:53 +09:00
|
|
|
}
|
|
|
|
|
2015-08-21 13:31:09 +02:00
|
|
|
// The left hand side must contain everything up to, and including, the
|
|
|
|
// assignment operator.
|
2017-11-16 11:26:36 +09:00
|
|
|
pub fn rewrite_assign_rhs<S: Into<String>, R: Rewrite>(
|
2017-06-12 15:58:58 +12:00
|
|
|
context: &RewriteContext,
|
|
|
|
lhs: S,
|
2017-11-16 11:26:36 +09:00
|
|
|
ex: &R,
|
2017-06-12 15:58:58 +12:00
|
|
|
shape: Shape,
|
2018-03-10 14:35:53 +09:00
|
|
|
) -> Option<String> {
|
|
|
|
rewrite_assign_rhs_with(context, lhs, ex, shape, RhsTactics::Default)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn rewrite_assign_rhs_with<S: Into<String>, R: Rewrite>(
|
|
|
|
context: &RewriteContext,
|
|
|
|
lhs: S,
|
|
|
|
ex: &R,
|
|
|
|
shape: Shape,
|
|
|
|
rhs_tactics: RhsTactics,
|
2017-06-12 15:58:58 +12:00
|
|
|
) -> Option<String> {
|
2017-07-10 02:22:59 +09:00
|
|
|
let lhs = lhs.into();
|
2018-05-14 21:58:57 +09:00
|
|
|
let last_line_width = last_line_width(&lhs).saturating_sub(if lhs.contains('\n') {
|
|
|
|
shape.indent.width()
|
|
|
|
} else {
|
|
|
|
0
|
|
|
|
});
|
2015-08-21 13:31:09 +02:00
|
|
|
// 1 = space between operator and rhs.
|
2017-11-21 08:52:11 +09:00
|
|
|
let orig_shape = shape.offset_left(last_line_width + 1).unwrap_or(Shape {
|
|
|
|
width: 0,
|
|
|
|
offset: shape.offset + last_line_width + 1,
|
|
|
|
..shape
|
|
|
|
});
|
2018-03-10 14:35:53 +09:00
|
|
|
let rhs = choose_rhs(
|
|
|
|
context,
|
|
|
|
ex,
|
|
|
|
orig_shape,
|
|
|
|
ex.rewrite(context, orig_shape),
|
|
|
|
rhs_tactics,
|
|
|
|
)?;
|
2017-07-10 02:22:59 +09:00
|
|
|
Some(lhs + &rhs)
|
|
|
|
}
|
2015-08-21 13:31:09 +02:00
|
|
|
|
2018-03-10 14:35:53 +09:00
|
|
|
fn choose_rhs<R: Rewrite>(
|
2017-07-10 02:22:59 +09:00
|
|
|
context: &RewriteContext,
|
2017-11-16 11:26:36 +09:00
|
|
|
expr: &R,
|
2017-07-10 02:22:59 +09:00
|
|
|
shape: Shape,
|
|
|
|
orig_rhs: Option<String>,
|
2018-03-10 14:35:53 +09:00
|
|
|
rhs_tactics: RhsTactics,
|
2017-07-10 02:22:59 +09:00
|
|
|
) -> Option<String> {
|
|
|
|
match orig_rhs {
|
2017-10-01 21:20:15 +09:00
|
|
|
Some(ref new_str) if !new_str.contains('\n') && new_str.len() <= shape.width => {
|
|
|
|
Some(format!(" {}", new_str))
|
|
|
|
}
|
2016-05-09 20:11:25 +02:00
|
|
|
_ => {
|
2017-07-05 18:30:11 +09:00
|
|
|
// Expression did not fit on the same line as the identifier.
|
|
|
|
// Try splitting the line and see if that works better.
|
2018-06-25 15:24:00 +09:00
|
|
|
let new_shape = shape_from_rhs_tactic(context, shape, rhs_tactics)?;
|
2017-07-10 02:22:59 +09:00
|
|
|
let new_rhs = expr.rewrite(context, new_shape);
|
2018-06-25 15:24:00 +09:00
|
|
|
let new_indent_str = &shape
|
|
|
|
.indent
|
|
|
|
.block_indent(context.config)
|
|
|
|
.to_string_with_newline(context.config);
|
2017-07-10 02:22:59 +09:00
|
|
|
|
|
|
|
match (orig_rhs, new_rhs) {
|
2017-11-24 12:05:02 +09:00
|
|
|
(Some(ref orig_rhs), Some(ref new_rhs))
|
|
|
|
if wrap_str(new_rhs.clone(), context.config.max_width(), new_shape)
|
|
|
|
.is_none() =>
|
|
|
|
{
|
|
|
|
Some(format!(" {}", orig_rhs))
|
|
|
|
}
|
2018-03-10 14:35:53 +09:00
|
|
|
(Some(ref orig_rhs), Some(ref new_rhs))
|
|
|
|
if prefer_next_line(orig_rhs, new_rhs, rhs_tactics) =>
|
|
|
|
{
|
2018-02-19 12:47:54 +09:00
|
|
|
Some(format!("{}{}", new_indent_str, new_rhs))
|
2016-05-09 20:11:25 +02:00
|
|
|
}
|
2018-02-19 12:47:54 +09:00
|
|
|
(None, Some(ref new_rhs)) => Some(format!("{}{}", new_indent_str, new_rhs)),
|
2017-07-10 02:22:59 +09:00
|
|
|
(None, None) => None,
|
2018-06-30 19:53:06 +12:00
|
|
|
(Some(orig_rhs), _) => Some(format!(" {}", orig_rhs)),
|
2016-05-09 20:11:25 +02:00
|
|
|
}
|
2015-08-21 13:31:09 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-09-24 01:13:57 -07:00
|
|
|
|
2018-06-25 15:24:00 +09:00
|
|
|
fn shape_from_rhs_tactic(
|
|
|
|
context: &RewriteContext,
|
|
|
|
shape: Shape,
|
|
|
|
rhs_tactic: RhsTactics,
|
|
|
|
) -> Option<Shape> {
|
|
|
|
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))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-21 22:02:18 +09:00
|
|
|
pub fn prefer_next_line(orig_rhs: &str, next_line_rhs: &str, rhs_tactics: RhsTactics) -> bool {
|
2018-06-25 15:24:00 +09:00
|
|
|
rhs_tactics == RhsTactics::ForceNextLineWithoutIndent
|
2018-05-06 15:22:29 +09:00
|
|
|
|| !next_line_rhs.contains('\n')
|
2018-03-10 14:35:53 +09:00
|
|
|
|| count_newlines(orig_rhs) > count_newlines(next_line_rhs) + 1
|
chains: prefer to use the next line for an expression, if using the same line would introduce an open block or similar
This problem came to light due to the chains changes, but effects other code too. It only happens rarely, e.g.,
before this fix:
```
match foo {
MacroArgKind::Delimited(ref delim_tok, ref args) => rewrite_delimited_inner(
delim_tok,
args,
).map(|(lhs, inner, rhs)| format!("{}{}{}", lhs, inner, rhs)),
};
```
after:
```
match foo {
MacroArgKind::Delimited(ref delim_tok, ref args) => {
rewrite_delimited_inner(delim_tok, args)
.map(|(lhs, inner, rhs)| format!("{}{}{}", lhs, inner, rhs))
}
}
```
2018-07-11 21:01:40 +12:00
|
|
|
|| 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, '[')
|
2017-07-05 18:30:11 +09:00
|
|
|
}
|
|
|
|
|
2017-06-12 15:58:58 +12:00
|
|
|
fn rewrite_expr_addrof(
|
|
|
|
context: &RewriteContext,
|
|
|
|
mutability: ast::Mutability,
|
|
|
|
expr: &ast::Expr,
|
|
|
|
shape: Shape,
|
|
|
|
) -> Option<String> {
|
2015-09-24 01:13:57 -07:00
|
|
|
let operator_str = match mutability {
|
2016-03-01 17:27:19 -05:00
|
|
|
ast::Mutability::Immutable => "&",
|
|
|
|
ast::Mutability::Mutable => "&mut ",
|
2015-09-24 01:13:57 -07:00
|
|
|
};
|
2017-05-15 22:55:01 +09:00
|
|
|
rewrite_unary_prefix(context, operator_str, expr, shape)
|
2015-09-24 01:13:57 -07:00
|
|
|
}
|
2017-06-14 09:29:39 +09:00
|
|
|
|
|
|
|
pub trait ToExpr {
|
|
|
|
fn to_expr(&self) -> Option<&ast::Expr>;
|
2017-06-15 16:25:40 +09:00
|
|
|
fn can_be_overflowed(&self, context: &RewriteContext, len: usize) -> bool;
|
2017-06-14 09:29:39 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
impl ToExpr for ast::Expr {
|
|
|
|
fn to_expr(&self) -> Option<&ast::Expr> {
|
|
|
|
Some(self)
|
|
|
|
}
|
2017-06-15 16:25:40 +09:00
|
|
|
|
|
|
|
fn can_be_overflowed(&self, context: &RewriteContext, len: usize) -> bool {
|
|
|
|
can_be_overflowed_expr(context, self, len)
|
|
|
|
}
|
2017-06-14 09:29:39 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
impl ToExpr for ast::Ty {
|
|
|
|
fn to_expr(&self) -> Option<&ast::Expr> {
|
|
|
|
None
|
|
|
|
}
|
2017-06-15 16:25:40 +09:00
|
|
|
|
|
|
|
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)
|
|
|
|
}
|
2017-06-14 09:29:39 +09:00
|
|
|
}
|
2017-06-24 19:46:36 +09:00
|
|
|
|
|
|
|
impl<'a> ToExpr for ast::StructField {
|
|
|
|
fn to_expr(&self) -> Option<&ast::Expr> {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
|
2017-06-24 19:49:01 +09:00
|
|
|
fn can_be_overflowed(&self, _: &RewriteContext, _: usize) -> bool {
|
2017-06-24 19:46:36 +09:00
|
|
|
false
|
|
|
|
}
|
|
|
|
}
|
2017-08-30 12:00:10 +09:00
|
|
|
|
|
|
|
impl<'a> ToExpr for MacroArg {
|
|
|
|
fn to_expr(&self) -> Option<&ast::Expr> {
|
2017-09-15 17:09:30 +09:00
|
|
|
match *self {
|
|
|
|
MacroArg::Expr(ref expr) => Some(expr),
|
2017-08-30 12:00:10 +09:00
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn can_be_overflowed(&self, context: &RewriteContext, len: usize) -> bool {
|
2017-09-15 17:09:30 +09:00
|
|
|
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,
|
2018-03-09 17:17:55 +09:00
|
|
|
MacroArg::Item(..) => len == 1,
|
2017-08-30 12:00:10 +09:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-03-07 15:48:47 +09:00
|
|
|
|
|
|
|
impl ToExpr for ast::GenericParam {
|
|
|
|
fn to_expr(&self) -> Option<&ast::Expr> {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
|
|
|
|
fn can_be_overflowed(&self, _: &RewriteContext, _: usize) -> bool {
|
|
|
|
false
|
|
|
|
}
|
|
|
|
}
|
2018-05-23 07:22:42 +09:00
|
|
|
|
|
|
|
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,
|
|
|
|
}
|
|
|
|
}
|