]> git.lizzy.rs Git - rust.git/blob - src/tools/rustfmt/src/expr.rs
Rollup merge of #93400 - ChayimFriedman2:dont-suggest-using-const-with-bounds-unused...
[rust.git] / src / tools / rustfmt / src / expr.rs
1 use std::borrow::Cow;
2 use std::cmp::min;
3
4 use itertools::Itertools;
5 use rustc_ast::token::{DelimToken, LitKind};
6 use rustc_ast::{ast, ptr};
7 use rustc_span::{BytePos, Span};
8
9 use crate::chains::rewrite_chain;
10 use crate::closures;
11 use crate::comment::{
12     combine_strs_with_missing_comments, contains_comment, recover_comment_removed, rewrite_comment,
13     rewrite_missing_comment, CharClasses, FindUncommented,
14 };
15 use crate::config::lists::*;
16 use crate::config::{Config, ControlBraceStyle, HexLiteralCase, IndentStyle, Version};
17 use crate::lists::{
18     definitive_tactic, itemize_list, shape_for_tactic, struct_lit_formatting, struct_lit_shape,
19     struct_lit_tactic, write_list, ListFormatting, Separator,
20 };
21 use crate::macros::{rewrite_macro, MacroPosition};
22 use crate::matches::rewrite_match;
23 use crate::overflow::{self, IntoOverflowableItem, OverflowableItem};
24 use crate::pairs::{rewrite_all_pairs, rewrite_pair, PairParts};
25 use crate::rewrite::{Rewrite, RewriteContext};
26 use crate::shape::{Indent, Shape};
27 use crate::source_map::{LineRangeUtils, SpanUtils};
28 use crate::spanned::Spanned;
29 use crate::string::{rewrite_string, StringFormat};
30 use crate::types::{rewrite_path, PathContext};
31 use crate::utils::{
32     colon_spaces, contains_skip, count_newlines, first_line_ends_with, inner_attributes,
33     last_line_extendable, last_line_width, mk_sp, outer_attributes, semicolon_for_expr,
34     unicode_str_width, wrap_str,
35 };
36 use crate::vertical::rewrite_with_alignment;
37 use crate::visitor::FmtVisitor;
38
39 impl Rewrite for ast::Expr {
40     fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
41         format_expr(self, ExprType::SubExpression, context, shape)
42     }
43 }
44
45 #[derive(Copy, Clone, PartialEq)]
46 pub(crate) enum ExprType {
47     Statement,
48     SubExpression,
49 }
50
51 pub(crate) fn format_expr(
52     expr: &ast::Expr,
53     expr_type: ExprType,
54     context: &RewriteContext<'_>,
55     shape: Shape,
56 ) -> Option<String> {
57     skip_out_of_file_lines_range!(context, expr.span);
58
59     if contains_skip(&*expr.attrs) {
60         return Some(context.snippet(expr.span()).to_owned());
61     }
62     let shape = if expr_type == ExprType::Statement && semicolon_for_expr(context, expr) {
63         shape.sub_width(1)?
64     } else {
65         shape
66     };
67
68     let expr_rw = match expr.kind {
69         ast::ExprKind::Array(ref expr_vec) => rewrite_array(
70             "",
71             expr_vec.iter(),
72             expr.span,
73             context,
74             shape,
75             choose_separator_tactic(context, expr.span),
76             None,
77         ),
78         ast::ExprKind::Lit(ref l) => {
79             if let Some(expr_rw) = rewrite_literal(context, l, shape) {
80                 Some(expr_rw)
81             } else {
82                 if let LitKind::StrRaw(_) = l.token.kind {
83                     Some(context.snippet(l.span).trim().into())
84                 } else {
85                     None
86                 }
87             }
88         }
89         ast::ExprKind::Call(ref callee, ref args) => {
90             let inner_span = mk_sp(callee.span.hi(), expr.span.hi());
91             let callee_str = callee.rewrite(context, shape)?;
92             rewrite_call(context, &callee_str, args, inner_span, shape)
93         }
94         ast::ExprKind::Paren(ref subexpr) => rewrite_paren(context, subexpr, shape, expr.span),
95         ast::ExprKind::Binary(op, ref lhs, ref rhs) => {
96             // FIXME: format comments between operands and operator
97             rewrite_all_pairs(expr, shape, context).or_else(|| {
98                 rewrite_pair(
99                     &**lhs,
100                     &**rhs,
101                     PairParts::infix(&format!(" {} ", context.snippet(op.span))),
102                     context,
103                     shape,
104                     context.config.binop_separator(),
105                 )
106             })
107         }
108         ast::ExprKind::Unary(op, ref subexpr) => rewrite_unary_op(context, op, subexpr, shape),
109         ast::ExprKind::Struct(ref struct_expr) => {
110             let ast::StructExpr {
111                 qself,
112                 fields,
113                 path,
114                 rest,
115             } = &**struct_expr;
116             rewrite_struct_lit(
117                 context,
118                 path,
119                 qself.as_ref(),
120                 fields,
121                 rest,
122                 &expr.attrs,
123                 expr.span,
124                 shape,
125             )
126         }
127         ast::ExprKind::Tup(ref items) => {
128             rewrite_tuple(context, items.iter(), expr.span, shape, items.len() == 1)
129         }
130         ast::ExprKind::Let(..) => None,
131         ast::ExprKind::If(..)
132         | ast::ExprKind::ForLoop(..)
133         | ast::ExprKind::Loop(..)
134         | ast::ExprKind::While(..) => to_control_flow(expr, expr_type)
135             .and_then(|control_flow| control_flow.rewrite(context, shape)),
136         ast::ExprKind::ConstBlock(ref anon_const) => {
137             Some(format!("const {}", anon_const.rewrite(context, shape)?))
138         }
139         ast::ExprKind::Block(ref block, opt_label) => {
140             match expr_type {
141                 ExprType::Statement => {
142                     if is_unsafe_block(block) {
143                         rewrite_block(block, Some(&expr.attrs), opt_label, context, shape)
144                     } else if let rw @ Some(_) =
145                         rewrite_empty_block(context, block, Some(&expr.attrs), opt_label, "", shape)
146                     {
147                         // Rewrite block without trying to put it in a single line.
148                         rw
149                     } else {
150                         let prefix = block_prefix(context, block, shape)?;
151
152                         rewrite_block_with_visitor(
153                             context,
154                             &prefix,
155                             block,
156                             Some(&expr.attrs),
157                             opt_label,
158                             shape,
159                             true,
160                         )
161                     }
162                 }
163                 ExprType::SubExpression => {
164                     rewrite_block(block, Some(&expr.attrs), opt_label, context, shape)
165                 }
166             }
167         }
168         ast::ExprKind::Match(ref cond, ref arms) => {
169             rewrite_match(context, cond, arms, shape, expr.span, &expr.attrs)
170         }
171         ast::ExprKind::Path(ref qself, ref path) => {
172             rewrite_path(context, PathContext::Expr, qself.as_ref(), path, shape)
173         }
174         ast::ExprKind::Assign(ref lhs, ref rhs, _) => {
175             rewrite_assignment(context, lhs, rhs, None, shape)
176         }
177         ast::ExprKind::AssignOp(ref op, ref lhs, ref rhs) => {
178             rewrite_assignment(context, lhs, rhs, Some(op), shape)
179         }
180         ast::ExprKind::Continue(ref opt_label) => {
181             let id_str = match *opt_label {
182                 Some(label) => format!(" {}", label.ident),
183                 None => String::new(),
184             };
185             Some(format!("continue{}", id_str))
186         }
187         ast::ExprKind::Break(ref opt_label, ref opt_expr) => {
188             let id_str = match *opt_label {
189                 Some(label) => format!(" {}", label.ident),
190                 None => String::new(),
191             };
192
193             if let Some(ref expr) = *opt_expr {
194                 rewrite_unary_prefix(context, &format!("break{} ", id_str), &**expr, shape)
195             } else {
196                 Some(format!("break{}", id_str))
197             }
198         }
199         ast::ExprKind::Yield(ref opt_expr) => {
200             if let Some(ref expr) = *opt_expr {
201                 rewrite_unary_prefix(context, "yield ", &**expr, shape)
202             } else {
203                 Some("yield".to_string())
204             }
205         }
206         ast::ExprKind::Closure(capture, ref is_async, movability, ref fn_decl, ref body, _) => {
207             closures::rewrite_closure(
208                 capture, is_async, movability, fn_decl, body, expr.span, context, shape,
209             )
210         }
211         ast::ExprKind::Try(..)
212         | ast::ExprKind::Field(..)
213         | ast::ExprKind::MethodCall(..)
214         | ast::ExprKind::Await(_) => rewrite_chain(expr, context, shape),
215         ast::ExprKind::MacCall(ref mac) => {
216             rewrite_macro(mac, None, context, shape, MacroPosition::Expression).or_else(|| {
217                 wrap_str(
218                     context.snippet(expr.span).to_owned(),
219                     context.config.max_width(),
220                     shape,
221                 )
222             })
223         }
224         ast::ExprKind::Ret(None) => Some("return".to_owned()),
225         ast::ExprKind::Ret(Some(ref expr)) => {
226             rewrite_unary_prefix(context, "return ", &**expr, shape)
227         }
228         ast::ExprKind::Box(ref expr) => rewrite_unary_prefix(context, "box ", &**expr, shape),
229         ast::ExprKind::AddrOf(borrow_kind, mutability, ref expr) => {
230             rewrite_expr_addrof(context, borrow_kind, mutability, expr, shape)
231         }
232         ast::ExprKind::Cast(ref expr, ref ty) => rewrite_pair(
233             &**expr,
234             &**ty,
235             PairParts::infix(" as "),
236             context,
237             shape,
238             SeparatorPlace::Front,
239         ),
240         ast::ExprKind::Type(ref expr, ref ty) => rewrite_pair(
241             &**expr,
242             &**ty,
243             PairParts::infix(": "),
244             context,
245             shape,
246             SeparatorPlace::Back,
247         ),
248         ast::ExprKind::Index(ref expr, ref index) => {
249             rewrite_index(&**expr, &**index, context, shape)
250         }
251         ast::ExprKind::Repeat(ref expr, ref repeats) => rewrite_pair(
252             &**expr,
253             &*repeats.value,
254             PairParts::new("[", "; ", "]"),
255             context,
256             shape,
257             SeparatorPlace::Back,
258         ),
259         ast::ExprKind::Range(ref lhs, ref rhs, limits) => {
260             let delim = match limits {
261                 ast::RangeLimits::HalfOpen => "..",
262                 ast::RangeLimits::Closed => "..=",
263             };
264
265             fn needs_space_before_range(context: &RewriteContext<'_>, lhs: &ast::Expr) -> bool {
266                 match lhs.kind {
267                     ast::ExprKind::Lit(ref lit) => match lit.kind {
268                         ast::LitKind::Float(_, ast::LitFloatType::Unsuffixed) => {
269                             context.snippet(lit.span).ends_with('.')
270                         }
271                         _ => false,
272                     },
273                     ast::ExprKind::Unary(_, ref expr) => needs_space_before_range(context, expr),
274                     _ => false,
275                 }
276             }
277
278             fn needs_space_after_range(rhs: &ast::Expr) -> bool {
279                 // Don't format `.. ..` into `....`, which is invalid.
280                 //
281                 // This check is unnecessary for `lhs`, because a range
282                 // starting from another range needs parentheses as `(x ..) ..`
283                 // (`x .. ..` is a range from `x` to `..`).
284                 matches!(rhs.kind, ast::ExprKind::Range(None, _, _))
285             }
286
287             let default_sp_delim = |lhs: Option<&ast::Expr>, rhs: Option<&ast::Expr>| {
288                 let space_if = |b: bool| if b { " " } else { "" };
289
290                 format!(
291                     "{}{}{}",
292                     lhs.map_or("", |lhs| space_if(needs_space_before_range(context, lhs))),
293                     delim,
294                     rhs.map_or("", |rhs| space_if(needs_space_after_range(rhs))),
295                 )
296             };
297
298             match (lhs.as_ref().map(|x| &**x), rhs.as_ref().map(|x| &**x)) {
299                 (Some(lhs), Some(rhs)) => {
300                     let sp_delim = if context.config.spaces_around_ranges() {
301                         format!(" {} ", delim)
302                     } else {
303                         default_sp_delim(Some(lhs), Some(rhs))
304                     };
305                     rewrite_pair(
306                         &*lhs,
307                         &*rhs,
308                         PairParts::infix(&sp_delim),
309                         context,
310                         shape,
311                         context.config.binop_separator(),
312                     )
313                 }
314                 (None, Some(rhs)) => {
315                     let sp_delim = if context.config.spaces_around_ranges() {
316                         format!("{} ", delim)
317                     } else {
318                         default_sp_delim(None, Some(rhs))
319                     };
320                     rewrite_unary_prefix(context, &sp_delim, &*rhs, shape)
321                 }
322                 (Some(lhs), None) => {
323                     let sp_delim = if context.config.spaces_around_ranges() {
324                         format!(" {}", delim)
325                     } else {
326                         default_sp_delim(Some(lhs), None)
327                     };
328                     rewrite_unary_suffix(context, &sp_delim, &*lhs, shape)
329                 }
330                 (None, None) => Some(delim.to_owned()),
331             }
332         }
333         // We do not format these expressions yet, but they should still
334         // satisfy our width restrictions.
335         // Style Guide RFC for InlineAsm variant pending
336         // https://github.com/rust-dev-tools/fmt-rfcs/issues/152
337         ast::ExprKind::InlineAsm(..) => Some(context.snippet(expr.span).to_owned()),
338         ast::ExprKind::TryBlock(ref block) => {
339             if let rw @ Some(_) =
340                 rewrite_single_line_block(context, "try ", block, Some(&expr.attrs), None, shape)
341             {
342                 rw
343             } else {
344                 // 9 = `try `
345                 let budget = shape.width.saturating_sub(9);
346                 Some(format!(
347                     "{}{}",
348                     "try ",
349                     rewrite_block(
350                         block,
351                         Some(&expr.attrs),
352                         None,
353                         context,
354                         Shape::legacy(budget, shape.indent)
355                     )?
356                 ))
357             }
358         }
359         ast::ExprKind::Async(capture_by, _node_id, ref block) => {
360             let mover = if capture_by == ast::CaptureBy::Value {
361                 "move "
362             } else {
363                 ""
364             };
365             if let rw @ Some(_) = rewrite_single_line_block(
366                 context,
367                 format!("{}{}", "async ", mover).as_str(),
368                 block,
369                 Some(&expr.attrs),
370                 None,
371                 shape,
372             ) {
373                 rw
374             } else {
375                 // 6 = `async `
376                 let budget = shape.width.saturating_sub(6);
377                 Some(format!(
378                     "{}{}{}",
379                     "async ",
380                     mover,
381                     rewrite_block(
382                         block,
383                         Some(&expr.attrs),
384                         None,
385                         context,
386                         Shape::legacy(budget, shape.indent)
387                     )?
388                 ))
389             }
390         }
391         ast::ExprKind::Underscore => Some("_".to_owned()),
392         ast::ExprKind::Err => None,
393     };
394
395     expr_rw
396         .and_then(|expr_str| recover_comment_removed(expr_str, expr.span, context))
397         .and_then(|expr_str| {
398             let attrs = outer_attributes(&expr.attrs);
399             let attrs_str = attrs.rewrite(context, shape)?;
400             let span = mk_sp(
401                 attrs.last().map_or(expr.span.lo(), |attr| attr.span.hi()),
402                 expr.span.lo(),
403             );
404             combine_strs_with_missing_comments(context, &attrs_str, &expr_str, span, shape, false)
405         })
406 }
407
408 pub(crate) fn rewrite_array<'a, T: 'a + IntoOverflowableItem<'a>>(
409     name: &'a str,
410     exprs: impl Iterator<Item = &'a T>,
411     span: Span,
412     context: &'a RewriteContext<'_>,
413     shape: Shape,
414     force_separator_tactic: Option<SeparatorTactic>,
415     delim_token: Option<DelimToken>,
416 ) -> Option<String> {
417     overflow::rewrite_with_square_brackets(
418         context,
419         name,
420         exprs,
421         shape,
422         span,
423         force_separator_tactic,
424         delim_token,
425     )
426 }
427
428 fn rewrite_empty_block(
429     context: &RewriteContext<'_>,
430     block: &ast::Block,
431     attrs: Option<&[ast::Attribute]>,
432     label: Option<ast::Label>,
433     prefix: &str,
434     shape: Shape,
435 ) -> Option<String> {
436     if block_has_statements(block) {
437         return None;
438     }
439
440     let label_str = rewrite_label(label);
441     if attrs.map_or(false, |a| !inner_attributes(a).is_empty()) {
442         return None;
443     }
444
445     if !block_contains_comment(context, block) && shape.width >= 2 {
446         return Some(format!("{}{}{{}}", prefix, label_str));
447     }
448
449     // If a block contains only a single-line comment, then leave it on one line.
450     let user_str = context.snippet(block.span);
451     let user_str = user_str.trim();
452     if user_str.starts_with('{') && user_str.ends_with('}') {
453         let comment_str = user_str[1..user_str.len() - 1].trim();
454         if block.stmts.is_empty()
455             && !comment_str.contains('\n')
456             && !comment_str.starts_with("//")
457             && comment_str.len() + 4 <= shape.width
458         {
459             return Some(format!("{}{}{{ {} }}", prefix, label_str, comment_str));
460         }
461     }
462
463     None
464 }
465
466 fn block_prefix(context: &RewriteContext<'_>, block: &ast::Block, shape: Shape) -> Option<String> {
467     Some(match block.rules {
468         ast::BlockCheckMode::Unsafe(..) => {
469             let snippet = context.snippet(block.span);
470             let open_pos = snippet.find_uncommented("{")?;
471             // Extract comment between unsafe and block start.
472             let trimmed = &snippet[6..open_pos].trim();
473
474             if !trimmed.is_empty() {
475                 // 9 = "unsafe  {".len(), 7 = "unsafe ".len()
476                 let budget = shape.width.checked_sub(9)?;
477                 format!(
478                     "unsafe {} ",
479                     rewrite_comment(
480                         trimmed,
481                         true,
482                         Shape::legacy(budget, shape.indent + 7),
483                         context.config,
484                     )?
485                 )
486             } else {
487                 "unsafe ".to_owned()
488             }
489         }
490         ast::BlockCheckMode::Default => String::new(),
491     })
492 }
493
494 fn rewrite_single_line_block(
495     context: &RewriteContext<'_>,
496     prefix: &str,
497     block: &ast::Block,
498     attrs: Option<&[ast::Attribute]>,
499     label: Option<ast::Label>,
500     shape: Shape,
501 ) -> Option<String> {
502     if is_simple_block(context, block, attrs) {
503         let expr_shape = shape.offset_left(last_line_width(prefix))?;
504         let expr_str = block.stmts[0].rewrite(context, expr_shape)?;
505         let label_str = rewrite_label(label);
506         let result = format!("{}{}{{ {} }}", prefix, label_str, expr_str);
507         if result.len() <= shape.width && !result.contains('\n') {
508             return Some(result);
509         }
510     }
511     None
512 }
513
514 pub(crate) fn rewrite_block_with_visitor(
515     context: &RewriteContext<'_>,
516     prefix: &str,
517     block: &ast::Block,
518     attrs: Option<&[ast::Attribute]>,
519     label: Option<ast::Label>,
520     shape: Shape,
521     has_braces: bool,
522 ) -> Option<String> {
523     if let rw @ Some(_) = rewrite_empty_block(context, block, attrs, label, prefix, shape) {
524         return rw;
525     }
526
527     let mut visitor = FmtVisitor::from_context(context);
528     visitor.block_indent = shape.indent;
529     visitor.is_if_else_block = context.is_if_else_block();
530     match (block.rules, label) {
531         (ast::BlockCheckMode::Unsafe(..), _) | (ast::BlockCheckMode::Default, Some(_)) => {
532             let snippet = context.snippet(block.span);
533             let open_pos = snippet.find_uncommented("{")?;
534             visitor.last_pos = block.span.lo() + BytePos(open_pos as u32)
535         }
536         (ast::BlockCheckMode::Default, None) => visitor.last_pos = block.span.lo(),
537     }
538
539     let inner_attrs = attrs.map(inner_attributes);
540     let label_str = rewrite_label(label);
541     visitor.visit_block(block, inner_attrs.as_deref(), has_braces);
542     let visitor_context = visitor.get_context();
543     context
544         .skipped_range
545         .borrow_mut()
546         .append(&mut visitor_context.skipped_range.borrow_mut());
547     Some(format!("{}{}{}", prefix, label_str, visitor.buffer))
548 }
549
550 impl Rewrite for ast::Block {
551     fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
552         rewrite_block(self, None, None, context, shape)
553     }
554 }
555
556 fn rewrite_block(
557     block: &ast::Block,
558     attrs: Option<&[ast::Attribute]>,
559     label: Option<ast::Label>,
560     context: &RewriteContext<'_>,
561     shape: Shape,
562 ) -> Option<String> {
563     let prefix = block_prefix(context, block, shape)?;
564
565     // shape.width is used only for the single line case: either the empty block `{}`,
566     // or an unsafe expression `unsafe { e }`.
567     if let rw @ Some(_) = rewrite_empty_block(context, block, attrs, label, &prefix, shape) {
568         return rw;
569     }
570
571     let result = rewrite_block_with_visitor(context, &prefix, block, attrs, label, shape, true);
572     if let Some(ref result_str) = result {
573         if result_str.lines().count() <= 3 {
574             if let rw @ Some(_) =
575                 rewrite_single_line_block(context, &prefix, block, attrs, label, shape)
576             {
577                 return rw;
578             }
579         }
580     }
581
582     result
583 }
584
585 // Rewrite condition if the given expression has one.
586 pub(crate) fn rewrite_cond(
587     context: &RewriteContext<'_>,
588     expr: &ast::Expr,
589     shape: Shape,
590 ) -> Option<String> {
591     match expr.kind {
592         ast::ExprKind::Match(ref cond, _) => {
593             // `match `cond` {`
594             let cond_shape = match context.config.indent_style() {
595                 IndentStyle::Visual => shape.shrink_left(6).and_then(|s| s.sub_width(2))?,
596                 IndentStyle::Block => shape.offset_left(8)?,
597             };
598             cond.rewrite(context, cond_shape)
599         }
600         _ => to_control_flow(expr, ExprType::SubExpression).and_then(|control_flow| {
601             let alt_block_sep =
602                 String::from("\n") + &shape.indent.block_only().to_string(context.config);
603             control_flow
604                 .rewrite_cond(context, shape, &alt_block_sep)
605                 .map(|rw| rw.0)
606         }),
607     }
608 }
609
610 // Abstraction over control flow expressions
611 #[derive(Debug)]
612 struct ControlFlow<'a> {
613     cond: Option<&'a ast::Expr>,
614     block: &'a ast::Block,
615     else_block: Option<&'a ast::Expr>,
616     label: Option<ast::Label>,
617     pat: Option<&'a ast::Pat>,
618     keyword: &'a str,
619     matcher: &'a str,
620     connector: &'a str,
621     allow_single_line: bool,
622     // HACK: `true` if this is an `if` expression in an `else if`.
623     nested_if: bool,
624     span: Span,
625 }
626
627 fn extract_pats_and_cond(expr: &ast::Expr) -> (Option<&ast::Pat>, &ast::Expr) {
628     match expr.kind {
629         ast::ExprKind::Let(ref pat, ref cond, _) => (Some(pat), cond),
630         _ => (None, expr),
631     }
632 }
633
634 // FIXME: Refactor this.
635 fn to_control_flow(expr: &ast::Expr, expr_type: ExprType) -> Option<ControlFlow<'_>> {
636     match expr.kind {
637         ast::ExprKind::If(ref cond, ref if_block, ref else_block) => {
638             let (pat, cond) = extract_pats_and_cond(cond);
639             Some(ControlFlow::new_if(
640                 cond,
641                 pat,
642                 if_block,
643                 else_block.as_ref().map(|e| &**e),
644                 expr_type == ExprType::SubExpression,
645                 false,
646                 expr.span,
647             ))
648         }
649         ast::ExprKind::ForLoop(ref pat, ref cond, ref block, label) => {
650             Some(ControlFlow::new_for(pat, cond, block, label, expr.span))
651         }
652         ast::ExprKind::Loop(ref block, label) => {
653             Some(ControlFlow::new_loop(block, label, expr.span))
654         }
655         ast::ExprKind::While(ref cond, ref block, label) => {
656             let (pat, cond) = extract_pats_and_cond(cond);
657             Some(ControlFlow::new_while(pat, cond, block, label, expr.span))
658         }
659         _ => None,
660     }
661 }
662
663 fn choose_matcher(pat: Option<&ast::Pat>) -> &'static str {
664     pat.map_or("", |_| "let")
665 }
666
667 impl<'a> ControlFlow<'a> {
668     fn new_if(
669         cond: &'a ast::Expr,
670         pat: Option<&'a ast::Pat>,
671         block: &'a ast::Block,
672         else_block: Option<&'a ast::Expr>,
673         allow_single_line: bool,
674         nested_if: bool,
675         span: Span,
676     ) -> ControlFlow<'a> {
677         let matcher = choose_matcher(pat);
678         ControlFlow {
679             cond: Some(cond),
680             block,
681             else_block,
682             label: None,
683             pat,
684             keyword: "if",
685             matcher,
686             connector: " =",
687             allow_single_line,
688             nested_if,
689             span,
690         }
691     }
692
693     fn new_loop(block: &'a ast::Block, label: Option<ast::Label>, span: Span) -> ControlFlow<'a> {
694         ControlFlow {
695             cond: None,
696             block,
697             else_block: None,
698             label,
699             pat: None,
700             keyword: "loop",
701             matcher: "",
702             connector: "",
703             allow_single_line: false,
704             nested_if: false,
705             span,
706         }
707     }
708
709     fn new_while(
710         pat: Option<&'a ast::Pat>,
711         cond: &'a ast::Expr,
712         block: &'a ast::Block,
713         label: Option<ast::Label>,
714         span: Span,
715     ) -> ControlFlow<'a> {
716         let matcher = choose_matcher(pat);
717         ControlFlow {
718             cond: Some(cond),
719             block,
720             else_block: None,
721             label,
722             pat,
723             keyword: "while",
724             matcher,
725             connector: " =",
726             allow_single_line: false,
727             nested_if: false,
728             span,
729         }
730     }
731
732     fn new_for(
733         pat: &'a ast::Pat,
734         cond: &'a ast::Expr,
735         block: &'a ast::Block,
736         label: Option<ast::Label>,
737         span: Span,
738     ) -> ControlFlow<'a> {
739         ControlFlow {
740             cond: Some(cond),
741             block,
742             else_block: None,
743             label,
744             pat: Some(pat),
745             keyword: "for",
746             matcher: "",
747             connector: " in",
748             allow_single_line: false,
749             nested_if: false,
750             span,
751         }
752     }
753
754     fn rewrite_single_line(
755         &self,
756         pat_expr_str: &str,
757         context: &RewriteContext<'_>,
758         width: usize,
759     ) -> Option<String> {
760         assert!(self.allow_single_line);
761         let else_block = self.else_block?;
762         let fixed_cost = self.keyword.len() + "  {  } else {  }".len();
763
764         if let ast::ExprKind::Block(ref else_node, _) = else_block.kind {
765             if !is_simple_block(context, self.block, None)
766                 || !is_simple_block(context, else_node, None)
767                 || pat_expr_str.contains('\n')
768             {
769                 return None;
770             }
771
772             let new_width = width.checked_sub(pat_expr_str.len() + fixed_cost)?;
773             let expr = &self.block.stmts[0];
774             let if_str = expr.rewrite(context, Shape::legacy(new_width, Indent::empty()))?;
775
776             let new_width = new_width.checked_sub(if_str.len())?;
777             let else_expr = &else_node.stmts[0];
778             let else_str = else_expr.rewrite(context, Shape::legacy(new_width, Indent::empty()))?;
779
780             if if_str.contains('\n') || else_str.contains('\n') {
781                 return None;
782             }
783
784             let result = format!(
785                 "{} {} {{ {} }} else {{ {} }}",
786                 self.keyword, pat_expr_str, if_str, else_str
787             );
788
789             if result.len() <= width {
790                 return Some(result);
791             }
792         }
793
794         None
795     }
796 }
797
798 /// Returns `true` if the last line of pat_str has leading whitespace and it is wider than the
799 /// shape's indent.
800 fn last_line_offsetted(start_column: usize, pat_str: &str) -> bool {
801     let mut leading_whitespaces = 0;
802     for c in pat_str.chars().rev() {
803         match c {
804             '\n' => break,
805             _ if c.is_whitespace() => leading_whitespaces += 1,
806             _ => leading_whitespaces = 0,
807         }
808     }
809     leading_whitespaces > start_column
810 }
811
812 impl<'a> ControlFlow<'a> {
813     fn rewrite_pat_expr(
814         &self,
815         context: &RewriteContext<'_>,
816         expr: &ast::Expr,
817         shape: Shape,
818         offset: usize,
819     ) -> Option<String> {
820         debug!("rewrite_pat_expr {:?} {:?} {:?}", shape, self.pat, expr);
821
822         let cond_shape = shape.offset_left(offset)?;
823         if let Some(pat) = self.pat {
824             let matcher = if self.matcher.is_empty() {
825                 self.matcher.to_owned()
826             } else {
827                 format!("{} ", self.matcher)
828             };
829             let pat_shape = cond_shape
830                 .offset_left(matcher.len())?
831                 .sub_width(self.connector.len())?;
832             let pat_string = pat.rewrite(context, pat_shape)?;
833             let comments_lo = context
834                 .snippet_provider
835                 .span_after(self.span.with_lo(pat.span.hi()), self.connector.trim());
836             let comments_span = mk_sp(comments_lo, expr.span.lo());
837             return rewrite_assign_rhs_with_comments(
838                 context,
839                 &format!("{}{}{}", matcher, pat_string, self.connector),
840                 expr,
841                 cond_shape,
842                 &RhsAssignKind::Expr(&expr.kind, expr.span),
843                 RhsTactics::Default,
844                 comments_span,
845                 true,
846             );
847         }
848
849         let expr_rw = expr.rewrite(context, cond_shape);
850         // The expression may (partially) fit on the current line.
851         // We do not allow splitting between `if` and condition.
852         if self.keyword == "if" || expr_rw.is_some() {
853             return expr_rw;
854         }
855
856         // The expression won't fit on the current line, jump to next.
857         let nested_shape = shape
858             .block_indent(context.config.tab_spaces())
859             .with_max_width(context.config);
860         let nested_indent_str = nested_shape.indent.to_string_with_newline(context.config);
861         expr.rewrite(context, nested_shape)
862             .map(|expr_rw| format!("{}{}", nested_indent_str, expr_rw))
863     }
864
865     fn rewrite_cond(
866         &self,
867         context: &RewriteContext<'_>,
868         shape: Shape,
869         alt_block_sep: &str,
870     ) -> Option<(String, usize)> {
871         // Do not take the rhs overhead from the upper expressions into account
872         // when rewriting pattern.
873         let new_width = context.budget(shape.used_width());
874         let fresh_shape = Shape {
875             width: new_width,
876             ..shape
877         };
878         let constr_shape = if self.nested_if {
879             // We are part of an if-elseif-else chain. Our constraints are tightened.
880             // 7 = "} else " .len()
881             fresh_shape.offset_left(7)?
882         } else {
883             fresh_shape
884         };
885
886         let label_string = rewrite_label(self.label);
887         // 1 = space after keyword.
888         let offset = self.keyword.len() + label_string.len() + 1;
889
890         let pat_expr_string = match self.cond {
891             Some(cond) => self.rewrite_pat_expr(context, cond, constr_shape, offset)?,
892             None => String::new(),
893         };
894
895         let brace_overhead =
896             if context.config.control_brace_style() != ControlBraceStyle::AlwaysNextLine {
897                 // 2 = ` {`
898                 2
899             } else {
900                 0
901             };
902         let one_line_budget = context
903             .config
904             .max_width()
905             .saturating_sub(constr_shape.used_width() + offset + brace_overhead);
906         let force_newline_brace = (pat_expr_string.contains('\n')
907             || pat_expr_string.len() > one_line_budget)
908             && (!last_line_extendable(&pat_expr_string)
909                 || last_line_offsetted(shape.used_width(), &pat_expr_string));
910
911         // Try to format if-else on single line.
912         if self.allow_single_line && context.config.single_line_if_else_max_width() > 0 {
913             let trial = self.rewrite_single_line(&pat_expr_string, context, shape.width);
914
915             if let Some(cond_str) = trial {
916                 if cond_str.len() <= context.config.single_line_if_else_max_width() {
917                     return Some((cond_str, 0));
918                 }
919             }
920         }
921
922         let cond_span = if let Some(cond) = self.cond {
923             cond.span
924         } else {
925             mk_sp(self.block.span.lo(), self.block.span.lo())
926         };
927
928         // `for event in event`
929         // Do not include label in the span.
930         let lo = self
931             .label
932             .map_or(self.span.lo(), |label| label.ident.span.hi());
933         let between_kwd_cond = mk_sp(
934             context
935                 .snippet_provider
936                 .span_after(mk_sp(lo, self.span.hi()), self.keyword.trim()),
937             if self.pat.is_none() {
938                 cond_span.lo()
939             } else if self.matcher.is_empty() {
940                 self.pat.unwrap().span.lo()
941             } else {
942                 context
943                     .snippet_provider
944                     .span_before(self.span, self.matcher.trim())
945             },
946         );
947
948         let between_kwd_cond_comment = extract_comment(between_kwd_cond, context, shape);
949
950         let after_cond_comment =
951             extract_comment(mk_sp(cond_span.hi(), self.block.span.lo()), context, shape);
952
953         let block_sep = if self.cond.is_none() && between_kwd_cond_comment.is_some() {
954             ""
955         } else if context.config.control_brace_style() == ControlBraceStyle::AlwaysNextLine
956             || force_newline_brace
957         {
958             alt_block_sep
959         } else {
960             " "
961         };
962
963         let used_width = if pat_expr_string.contains('\n') {
964             last_line_width(&pat_expr_string)
965         } else {
966             // 2 = spaces after keyword and condition.
967             label_string.len() + self.keyword.len() + pat_expr_string.len() + 2
968         };
969
970         Some((
971             format!(
972                 "{}{}{}{}{}",
973                 label_string,
974                 self.keyword,
975                 between_kwd_cond_comment.as_ref().map_or(
976                     if pat_expr_string.is_empty() || pat_expr_string.starts_with('\n') {
977                         ""
978                     } else {
979                         " "
980                     },
981                     |s| &**s,
982                 ),
983                 pat_expr_string,
984                 after_cond_comment.as_ref().map_or(block_sep, |s| &**s)
985             ),
986             used_width,
987         ))
988     }
989 }
990
991 impl<'a> Rewrite for ControlFlow<'a> {
992     fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
993         debug!("ControlFlow::rewrite {:?} {:?}", self, shape);
994
995         let alt_block_sep = &shape.indent.to_string_with_newline(context.config);
996         let (cond_str, used_width) = self.rewrite_cond(context, shape, alt_block_sep)?;
997         // If `used_width` is 0, it indicates that whole control flow is written in a single line.
998         if used_width == 0 {
999             return Some(cond_str);
1000         }
1001
1002         let block_width = shape.width.saturating_sub(used_width);
1003         // This is used only for the empty block case: `{}`. So, we use 1 if we know
1004         // we should avoid the single line case.
1005         let block_width = if self.else_block.is_some() || self.nested_if {
1006             min(1, block_width)
1007         } else {
1008             block_width
1009         };
1010         let block_shape = Shape {
1011             width: block_width,
1012             ..shape
1013         };
1014         let block_str = {
1015             let old_val = context.is_if_else_block.replace(self.else_block.is_some());
1016             let result =
1017                 rewrite_block_with_visitor(context, "", self.block, None, None, block_shape, true);
1018             context.is_if_else_block.replace(old_val);
1019             result?
1020         };
1021
1022         let mut result = format!("{}{}", cond_str, block_str);
1023
1024         if let Some(else_block) = self.else_block {
1025             let shape = Shape::indented(shape.indent, context.config);
1026             let mut last_in_chain = false;
1027             let rewrite = match else_block.kind {
1028                 // If the else expression is another if-else expression, prevent it
1029                 // from being formatted on a single line.
1030                 // Note how we're passing the original shape, as the
1031                 // cost of "else" should not cascade.
1032                 ast::ExprKind::If(ref cond, ref if_block, ref next_else_block) => {
1033                     let (pats, cond) = extract_pats_and_cond(cond);
1034                     ControlFlow::new_if(
1035                         cond,
1036                         pats,
1037                         if_block,
1038                         next_else_block.as_ref().map(|e| &**e),
1039                         false,
1040                         true,
1041                         mk_sp(else_block.span.lo(), self.span.hi()),
1042                     )
1043                     .rewrite(context, shape)
1044                 }
1045                 _ => {
1046                     last_in_chain = true;
1047                     // When rewriting a block, the width is only used for single line
1048                     // blocks, passing 1 lets us avoid that.
1049                     let else_shape = Shape {
1050                         width: min(1, shape.width),
1051                         ..shape
1052                     };
1053                     format_expr(else_block, ExprType::Statement, context, else_shape)
1054                 }
1055             };
1056
1057             let between_kwd_else_block = mk_sp(
1058                 self.block.span.hi(),
1059                 context
1060                     .snippet_provider
1061                     .span_before(mk_sp(self.block.span.hi(), else_block.span.lo()), "else"),
1062             );
1063             let between_kwd_else_block_comment =
1064                 extract_comment(between_kwd_else_block, context, shape);
1065
1066             let after_else = mk_sp(
1067                 context
1068                     .snippet_provider
1069                     .span_after(mk_sp(self.block.span.hi(), else_block.span.lo()), "else"),
1070                 else_block.span.lo(),
1071             );
1072             let after_else_comment = extract_comment(after_else, context, shape);
1073
1074             let between_sep = match context.config.control_brace_style() {
1075                 ControlBraceStyle::AlwaysNextLine | ControlBraceStyle::ClosingNextLine => {
1076                     &*alt_block_sep
1077                 }
1078                 ControlBraceStyle::AlwaysSameLine => " ",
1079             };
1080             let after_sep = match context.config.control_brace_style() {
1081                 ControlBraceStyle::AlwaysNextLine if last_in_chain => &*alt_block_sep,
1082                 _ => " ",
1083             };
1084
1085             result.push_str(&format!(
1086                 "{}else{}",
1087                 between_kwd_else_block_comment
1088                     .as_ref()
1089                     .map_or(between_sep, |s| &**s),
1090                 after_else_comment.as_ref().map_or(after_sep, |s| &**s),
1091             ));
1092             result.push_str(&rewrite?);
1093         }
1094
1095         Some(result)
1096     }
1097 }
1098
1099 fn rewrite_label(opt_label: Option<ast::Label>) -> Cow<'static, str> {
1100     match opt_label {
1101         Some(label) => Cow::from(format!("{}: ", label.ident)),
1102         None => Cow::from(""),
1103     }
1104 }
1105
1106 fn extract_comment(span: Span, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
1107     match rewrite_missing_comment(span, shape, context) {
1108         Some(ref comment) if !comment.is_empty() => Some(format!(
1109             "{indent}{}{indent}",
1110             comment,
1111             indent = shape.indent.to_string_with_newline(context.config)
1112         )),
1113         _ => None,
1114     }
1115 }
1116
1117 pub(crate) fn block_contains_comment(context: &RewriteContext<'_>, block: &ast::Block) -> bool {
1118     contains_comment(context.snippet(block.span))
1119 }
1120
1121 // Checks that a block contains no statements, an expression and no comments or
1122 // attributes.
1123 // FIXME: incorrectly returns false when comment is contained completely within
1124 // the expression.
1125 pub(crate) fn is_simple_block(
1126     context: &RewriteContext<'_>,
1127     block: &ast::Block,
1128     attrs: Option<&[ast::Attribute]>,
1129 ) -> bool {
1130     block.stmts.len() == 1
1131         && stmt_is_expr(&block.stmts[0])
1132         && !block_contains_comment(context, block)
1133         && attrs.map_or(true, |a| a.is_empty())
1134 }
1135
1136 /// Checks whether a block contains at most one statement or expression, and no
1137 /// comments or attributes.
1138 pub(crate) fn is_simple_block_stmt(
1139     context: &RewriteContext<'_>,
1140     block: &ast::Block,
1141     attrs: Option<&[ast::Attribute]>,
1142 ) -> bool {
1143     block.stmts.len() <= 1
1144         && !block_contains_comment(context, block)
1145         && attrs.map_or(true, |a| a.is_empty())
1146 }
1147
1148 fn block_has_statements(block: &ast::Block) -> bool {
1149     block
1150         .stmts
1151         .iter()
1152         .any(|stmt| !matches!(stmt.kind, ast::StmtKind::Empty))
1153 }
1154
1155 /// Checks whether a block contains no statements, expressions, comments, or
1156 /// inner attributes.
1157 pub(crate) fn is_empty_block(
1158     context: &RewriteContext<'_>,
1159     block: &ast::Block,
1160     attrs: Option<&[ast::Attribute]>,
1161 ) -> bool {
1162     !block_has_statements(block)
1163         && !block_contains_comment(context, block)
1164         && attrs.map_or(true, |a| inner_attributes(a).is_empty())
1165 }
1166
1167 pub(crate) fn stmt_is_expr(stmt: &ast::Stmt) -> bool {
1168     matches!(stmt.kind, ast::StmtKind::Expr(..))
1169 }
1170
1171 pub(crate) fn is_unsafe_block(block: &ast::Block) -> bool {
1172     matches!(block.rules, ast::BlockCheckMode::Unsafe(..))
1173 }
1174
1175 pub(crate) fn rewrite_literal(
1176     context: &RewriteContext<'_>,
1177     l: &ast::Lit,
1178     shape: Shape,
1179 ) -> Option<String> {
1180     match l.kind {
1181         ast::LitKind::Str(_, ast::StrStyle::Cooked) => rewrite_string_lit(context, l.span, shape),
1182         ast::LitKind::Int(..) => rewrite_int_lit(context, l, shape),
1183         _ => wrap_str(
1184             context.snippet(l.span).to_owned(),
1185             context.config.max_width(),
1186             shape,
1187         ),
1188     }
1189 }
1190
1191 fn rewrite_string_lit(context: &RewriteContext<'_>, span: Span, shape: Shape) -> Option<String> {
1192     let string_lit = context.snippet(span);
1193
1194     if !context.config.format_strings() {
1195         if string_lit
1196             .lines()
1197             .dropping_back(1)
1198             .all(|line| line.ends_with('\\'))
1199             && context.config.version() == Version::Two
1200         {
1201             return Some(string_lit.to_owned());
1202         } else {
1203             return wrap_str(string_lit.to_owned(), context.config.max_width(), shape);
1204         }
1205     }
1206
1207     // Remove the quote characters.
1208     let str_lit = &string_lit[1..string_lit.len() - 1];
1209
1210     rewrite_string(
1211         str_lit,
1212         &StringFormat::new(shape.visual_indent(0), context.config),
1213         shape.width.saturating_sub(2),
1214     )
1215 }
1216
1217 fn rewrite_int_lit(context: &RewriteContext<'_>, lit: &ast::Lit, shape: Shape) -> Option<String> {
1218     let span = lit.span;
1219     let symbol = lit.token.symbol.as_str();
1220
1221     if let Some(symbol_stripped) = symbol.strip_prefix("0x") {
1222         let hex_lit = match context.config.hex_literal_case() {
1223             HexLiteralCase::Preserve => None,
1224             HexLiteralCase::Upper => Some(symbol_stripped.to_ascii_uppercase()),
1225             HexLiteralCase::Lower => Some(symbol_stripped.to_ascii_lowercase()),
1226         };
1227         if let Some(hex_lit) = hex_lit {
1228             return wrap_str(
1229                 format!(
1230                     "0x{}{}",
1231                     hex_lit,
1232                     lit.token.suffix.map_or(String::new(), |s| s.to_string())
1233                 ),
1234                 context.config.max_width(),
1235                 shape,
1236             );
1237         }
1238     }
1239
1240     wrap_str(
1241         context.snippet(span).to_owned(),
1242         context.config.max_width(),
1243         shape,
1244     )
1245 }
1246
1247 fn choose_separator_tactic(context: &RewriteContext<'_>, span: Span) -> Option<SeparatorTactic> {
1248     if context.inside_macro() {
1249         if span_ends_with_comma(context, span) {
1250             Some(SeparatorTactic::Always)
1251         } else {
1252             Some(SeparatorTactic::Never)
1253         }
1254     } else {
1255         None
1256     }
1257 }
1258
1259 pub(crate) fn rewrite_call(
1260     context: &RewriteContext<'_>,
1261     callee: &str,
1262     args: &[ptr::P<ast::Expr>],
1263     span: Span,
1264     shape: Shape,
1265 ) -> Option<String> {
1266     overflow::rewrite_with_parens(
1267         context,
1268         callee,
1269         args.iter(),
1270         shape,
1271         span,
1272         context.config.fn_call_width(),
1273         choose_separator_tactic(context, span),
1274     )
1275 }
1276
1277 pub(crate) fn is_simple_expr(expr: &ast::Expr) -> bool {
1278     match expr.kind {
1279         ast::ExprKind::Lit(..) => true,
1280         ast::ExprKind::Path(ref qself, ref path) => qself.is_none() && path.segments.len() <= 1,
1281         ast::ExprKind::AddrOf(_, _, ref expr)
1282         | ast::ExprKind::Box(ref expr)
1283         | ast::ExprKind::Cast(ref expr, _)
1284         | ast::ExprKind::Field(ref expr, _)
1285         | ast::ExprKind::Try(ref expr)
1286         | ast::ExprKind::Unary(_, ref expr) => is_simple_expr(expr),
1287         ast::ExprKind::Index(ref lhs, ref rhs) => is_simple_expr(lhs) && is_simple_expr(rhs),
1288         ast::ExprKind::Repeat(ref lhs, ref rhs) => {
1289             is_simple_expr(lhs) && is_simple_expr(&*rhs.value)
1290         }
1291         _ => false,
1292     }
1293 }
1294
1295 pub(crate) fn is_every_expr_simple(lists: &[OverflowableItem<'_>]) -> bool {
1296     lists.iter().all(OverflowableItem::is_simple)
1297 }
1298
1299 pub(crate) fn can_be_overflowed_expr(
1300     context: &RewriteContext<'_>,
1301     expr: &ast::Expr,
1302     args_len: usize,
1303 ) -> bool {
1304     match expr.kind {
1305         _ if !expr.attrs.is_empty() => false,
1306         ast::ExprKind::Match(..) => {
1307             (context.use_block_indent() && args_len == 1)
1308                 || (context.config.indent_style() == IndentStyle::Visual && args_len > 1)
1309                 || context.config.overflow_delimited_expr()
1310         }
1311         ast::ExprKind::If(..)
1312         | ast::ExprKind::ForLoop(..)
1313         | ast::ExprKind::Loop(..)
1314         | ast::ExprKind::While(..) => {
1315             context.config.combine_control_expr() && context.use_block_indent() && args_len == 1
1316         }
1317
1318         // Handle always block-like expressions
1319         ast::ExprKind::Async(..) | ast::ExprKind::Block(..) | ast::ExprKind::Closure(..) => true,
1320
1321         // Handle `[]` and `{}`-like expressions
1322         ast::ExprKind::Array(..) | ast::ExprKind::Struct(..) => {
1323             context.config.overflow_delimited_expr()
1324                 || (context.use_block_indent() && args_len == 1)
1325         }
1326         ast::ExprKind::MacCall(ref mac) => {
1327             match (
1328                 rustc_ast::ast::MacDelimiter::from_token(mac.args.delim()),
1329                 context.config.overflow_delimited_expr(),
1330             ) {
1331                 (Some(ast::MacDelimiter::Bracket), true)
1332                 | (Some(ast::MacDelimiter::Brace), true) => true,
1333                 _ => context.use_block_indent() && args_len == 1,
1334             }
1335         }
1336
1337         // Handle parenthetical expressions
1338         ast::ExprKind::Call(..) | ast::ExprKind::MethodCall(..) | ast::ExprKind::Tup(..) => {
1339             context.use_block_indent() && args_len == 1
1340         }
1341
1342         // Handle unary-like expressions
1343         ast::ExprKind::AddrOf(_, _, ref expr)
1344         | ast::ExprKind::Box(ref expr)
1345         | ast::ExprKind::Try(ref expr)
1346         | ast::ExprKind::Unary(_, ref expr)
1347         | ast::ExprKind::Cast(ref expr, _) => can_be_overflowed_expr(context, expr, args_len),
1348         _ => false,
1349     }
1350 }
1351
1352 pub(crate) fn is_nested_call(expr: &ast::Expr) -> bool {
1353     match expr.kind {
1354         ast::ExprKind::Call(..) | ast::ExprKind::MacCall(..) => true,
1355         ast::ExprKind::AddrOf(_, _, ref expr)
1356         | ast::ExprKind::Box(ref expr)
1357         | ast::ExprKind::Try(ref expr)
1358         | ast::ExprKind::Unary(_, ref expr)
1359         | ast::ExprKind::Cast(ref expr, _) => is_nested_call(expr),
1360         _ => false,
1361     }
1362 }
1363
1364 /// Returns `true` if a function call or a method call represented by the given span ends with a
1365 /// trailing comma. This function is used when rewriting macro, as adding or removing a trailing
1366 /// comma from macro can potentially break the code.
1367 pub(crate) fn span_ends_with_comma(context: &RewriteContext<'_>, span: Span) -> bool {
1368     let mut result: bool = Default::default();
1369     let mut prev_char: char = Default::default();
1370     let closing_delimiters = &[')', '}', ']'];
1371
1372     for (kind, c) in CharClasses::new(context.snippet(span).chars()) {
1373         match c {
1374             _ if kind.is_comment() || c.is_whitespace() => continue,
1375             c if closing_delimiters.contains(&c) => {
1376                 result &= !closing_delimiters.contains(&prev_char);
1377             }
1378             ',' => result = true,
1379             _ => result = false,
1380         }
1381         prev_char = c;
1382     }
1383
1384     result
1385 }
1386
1387 fn rewrite_paren(
1388     context: &RewriteContext<'_>,
1389     mut subexpr: &ast::Expr,
1390     shape: Shape,
1391     mut span: Span,
1392 ) -> Option<String> {
1393     debug!("rewrite_paren, shape: {:?}", shape);
1394
1395     // Extract comments within parens.
1396     let mut pre_span;
1397     let mut post_span;
1398     let mut pre_comment;
1399     let mut post_comment;
1400     let remove_nested_parens = context.config.remove_nested_parens();
1401     loop {
1402         // 1 = "(" or ")"
1403         pre_span = mk_sp(span.lo() + BytePos(1), subexpr.span.lo());
1404         post_span = mk_sp(subexpr.span.hi(), span.hi() - BytePos(1));
1405         pre_comment = rewrite_missing_comment(pre_span, shape, context)?;
1406         post_comment = rewrite_missing_comment(post_span, shape, context)?;
1407
1408         // Remove nested parens if there are no comments.
1409         if let ast::ExprKind::Paren(ref subsubexpr) = subexpr.kind {
1410             if remove_nested_parens && pre_comment.is_empty() && post_comment.is_empty() {
1411                 span = subexpr.span;
1412                 subexpr = subsubexpr;
1413                 continue;
1414             }
1415         }
1416
1417         break;
1418     }
1419
1420     // 1 = `(` and `)`
1421     let sub_shape = shape.offset_left(1)?.sub_width(1)?;
1422     let subexpr_str = subexpr.rewrite(context, sub_shape)?;
1423     let fits_single_line = !pre_comment.contains("//") && !post_comment.contains("//");
1424     if fits_single_line {
1425         Some(format!("({}{}{})", pre_comment, subexpr_str, post_comment))
1426     } else {
1427         rewrite_paren_in_multi_line(context, subexpr, shape, pre_span, post_span)
1428     }
1429 }
1430
1431 fn rewrite_paren_in_multi_line(
1432     context: &RewriteContext<'_>,
1433     subexpr: &ast::Expr,
1434     shape: Shape,
1435     pre_span: Span,
1436     post_span: Span,
1437 ) -> Option<String> {
1438     let nested_indent = shape.indent.block_indent(context.config);
1439     let nested_shape = Shape::indented(nested_indent, context.config);
1440     let pre_comment = rewrite_missing_comment(pre_span, nested_shape, context)?;
1441     let post_comment = rewrite_missing_comment(post_span, nested_shape, context)?;
1442     let subexpr_str = subexpr.rewrite(context, nested_shape)?;
1443
1444     let mut result = String::with_capacity(subexpr_str.len() * 2);
1445     result.push('(');
1446     if !pre_comment.is_empty() {
1447         result.push_str(&nested_indent.to_string_with_newline(context.config));
1448         result.push_str(&pre_comment);
1449     }
1450     result.push_str(&nested_indent.to_string_with_newline(context.config));
1451     result.push_str(&subexpr_str);
1452     if !post_comment.is_empty() {
1453         result.push_str(&nested_indent.to_string_with_newline(context.config));
1454         result.push_str(&post_comment);
1455     }
1456     result.push_str(&shape.indent.to_string_with_newline(context.config));
1457     result.push(')');
1458
1459     Some(result)
1460 }
1461
1462 fn rewrite_index(
1463     expr: &ast::Expr,
1464     index: &ast::Expr,
1465     context: &RewriteContext<'_>,
1466     shape: Shape,
1467 ) -> Option<String> {
1468     let expr_str = expr.rewrite(context, shape)?;
1469
1470     let offset = last_line_width(&expr_str) + 1;
1471     let rhs_overhead = shape.rhs_overhead(context.config);
1472     let index_shape = if expr_str.contains('\n') {
1473         Shape::legacy(context.config.max_width(), shape.indent)
1474             .offset_left(offset)
1475             .and_then(|shape| shape.sub_width(1 + rhs_overhead))
1476     } else {
1477         match context.config.indent_style() {
1478             IndentStyle::Block => shape
1479                 .offset_left(offset)
1480                 .and_then(|shape| shape.sub_width(1)),
1481             IndentStyle::Visual => shape.visual_indent(offset).sub_width(offset + 1),
1482         }
1483     };
1484     let orig_index_rw = index_shape.and_then(|s| index.rewrite(context, s));
1485
1486     // Return if index fits in a single line.
1487     match orig_index_rw {
1488         Some(ref index_str) if !index_str.contains('\n') => {
1489             return Some(format!("{}[{}]", expr_str, index_str));
1490         }
1491         _ => (),
1492     }
1493
1494     // Try putting index on the next line and see if it fits in a single line.
1495     let indent = shape.indent.block_indent(context.config);
1496     let index_shape = Shape::indented(indent, context.config).offset_left(1)?;
1497     let index_shape = index_shape.sub_width(1 + rhs_overhead)?;
1498     let new_index_rw = index.rewrite(context, index_shape);
1499     match (orig_index_rw, new_index_rw) {
1500         (_, Some(ref new_index_str)) if !new_index_str.contains('\n') => Some(format!(
1501             "{}{}[{}]",
1502             expr_str,
1503             indent.to_string_with_newline(context.config),
1504             new_index_str,
1505         )),
1506         (None, Some(ref new_index_str)) => Some(format!(
1507             "{}{}[{}]",
1508             expr_str,
1509             indent.to_string_with_newline(context.config),
1510             new_index_str,
1511         )),
1512         (Some(ref index_str), _) => Some(format!("{}[{}]", expr_str, index_str)),
1513         _ => None,
1514     }
1515 }
1516
1517 fn struct_lit_can_be_aligned(fields: &[ast::ExprField], has_base: bool) -> bool {
1518     !has_base && fields.iter().all(|field| !field.is_shorthand)
1519 }
1520
1521 fn rewrite_struct_lit<'a>(
1522     context: &RewriteContext<'_>,
1523     path: &ast::Path,
1524     qself: Option<&ast::QSelf>,
1525     fields: &'a [ast::ExprField],
1526     struct_rest: &ast::StructRest,
1527     attrs: &[ast::Attribute],
1528     span: Span,
1529     shape: Shape,
1530 ) -> Option<String> {
1531     debug!("rewrite_struct_lit: shape {:?}", shape);
1532
1533     enum StructLitField<'a> {
1534         Regular(&'a ast::ExprField),
1535         Base(&'a ast::Expr),
1536         Rest(Span),
1537     }
1538
1539     // 2 = " {".len()
1540     let path_shape = shape.sub_width(2)?;
1541     let path_str = rewrite_path(context, PathContext::Expr, qself, path, path_shape)?;
1542
1543     let has_base_or_rest = match struct_rest {
1544         ast::StructRest::None if fields.is_empty() => return Some(format!("{} {{}}", path_str)),
1545         ast::StructRest::Rest(_) if fields.is_empty() => {
1546             return Some(format!("{} {{ .. }}", path_str));
1547         }
1548         ast::StructRest::Rest(_) | ast::StructRest::Base(_) => true,
1549         _ => false,
1550     };
1551
1552     // Foo { a: Foo } - indent is +3, width is -5.
1553     let (h_shape, v_shape) = struct_lit_shape(shape, context, path_str.len() + 3, 2)?;
1554
1555     let one_line_width = h_shape.map_or(0, |shape| shape.width);
1556     let body_lo = context.snippet_provider.span_after(span, "{");
1557     let fields_str = if struct_lit_can_be_aligned(fields, has_base_or_rest)
1558         && context.config.struct_field_align_threshold() > 0
1559     {
1560         rewrite_with_alignment(
1561             fields,
1562             context,
1563             v_shape,
1564             mk_sp(body_lo, span.hi()),
1565             one_line_width,
1566         )?
1567     } else {
1568         let field_iter = fields.iter().map(StructLitField::Regular).chain(
1569             match struct_rest {
1570                 ast::StructRest::Base(expr) => Some(StructLitField::Base(&**expr)),
1571                 ast::StructRest::Rest(span) => Some(StructLitField::Rest(*span)),
1572                 ast::StructRest::None => None,
1573             }
1574             .into_iter(),
1575         );
1576
1577         let span_lo = |item: &StructLitField<'_>| match *item {
1578             StructLitField::Regular(field) => field.span().lo(),
1579             StructLitField::Base(expr) => {
1580                 let last_field_hi = fields.last().map_or(span.lo(), |field| field.span.hi());
1581                 let snippet = context.snippet(mk_sp(last_field_hi, expr.span.lo()));
1582                 let pos = snippet.find_uncommented("..").unwrap();
1583                 last_field_hi + BytePos(pos as u32)
1584             }
1585             StructLitField::Rest(span) => span.lo(),
1586         };
1587         let span_hi = |item: &StructLitField<'_>| match *item {
1588             StructLitField::Regular(field) => field.span().hi(),
1589             StructLitField::Base(expr) => expr.span.hi(),
1590             StructLitField::Rest(span) => span.hi(),
1591         };
1592         let rewrite = |item: &StructLitField<'_>| match *item {
1593             StructLitField::Regular(field) => {
1594                 // The 1 taken from the v_budget is for the comma.
1595                 rewrite_field(context, field, v_shape.sub_width(1)?, 0)
1596             }
1597             StructLitField::Base(expr) => {
1598                 // 2 = ..
1599                 expr.rewrite(context, v_shape.offset_left(2)?)
1600                     .map(|s| format!("..{}", s))
1601             }
1602             StructLitField::Rest(_) => Some("..".to_owned()),
1603         };
1604
1605         let items = itemize_list(
1606             context.snippet_provider,
1607             field_iter,
1608             "}",
1609             ",",
1610             span_lo,
1611             span_hi,
1612             rewrite,
1613             body_lo,
1614             span.hi(),
1615             false,
1616         );
1617         let item_vec = items.collect::<Vec<_>>();
1618
1619         let tactic = struct_lit_tactic(h_shape, context, &item_vec);
1620         let nested_shape = shape_for_tactic(tactic, h_shape, v_shape);
1621
1622         let ends_with_comma = span_ends_with_comma(context, span);
1623         let force_no_trailing_comma = context.inside_macro() && !ends_with_comma;
1624
1625         let fmt = struct_lit_formatting(
1626             nested_shape,
1627             tactic,
1628             context,
1629             force_no_trailing_comma || has_base_or_rest || !context.use_block_indent(),
1630         );
1631
1632         write_list(&item_vec, &fmt)?
1633     };
1634
1635     let fields_str =
1636         wrap_struct_field(context, attrs, &fields_str, shape, v_shape, one_line_width)?;
1637     Some(format!("{} {{{}}}", path_str, fields_str))
1638
1639     // FIXME if context.config.indent_style() == Visual, but we run out
1640     // of space, we should fall back to BlockIndent.
1641 }
1642
1643 pub(crate) fn wrap_struct_field(
1644     context: &RewriteContext<'_>,
1645     attrs: &[ast::Attribute],
1646     fields_str: &str,
1647     shape: Shape,
1648     nested_shape: Shape,
1649     one_line_width: usize,
1650 ) -> Option<String> {
1651     let should_vertical = context.config.indent_style() == IndentStyle::Block
1652         && (fields_str.contains('\n')
1653             || !context.config.struct_lit_single_line()
1654             || fields_str.len() > one_line_width);
1655
1656     let inner_attrs = &inner_attributes(attrs);
1657     if inner_attrs.is_empty() {
1658         if should_vertical {
1659             Some(format!(
1660                 "{}{}{}",
1661                 nested_shape.indent.to_string_with_newline(context.config),
1662                 fields_str,
1663                 shape.indent.to_string_with_newline(context.config)
1664             ))
1665         } else {
1666             // One liner or visual indent.
1667             Some(format!(" {} ", fields_str))
1668         }
1669     } else {
1670         Some(format!(
1671             "{}{}{}{}{}",
1672             nested_shape.indent.to_string_with_newline(context.config),
1673             inner_attrs.rewrite(context, shape)?,
1674             nested_shape.indent.to_string_with_newline(context.config),
1675             fields_str,
1676             shape.indent.to_string_with_newline(context.config)
1677         ))
1678     }
1679 }
1680
1681 pub(crate) fn struct_lit_field_separator(config: &Config) -> &str {
1682     colon_spaces(config)
1683 }
1684
1685 pub(crate) fn rewrite_field(
1686     context: &RewriteContext<'_>,
1687     field: &ast::ExprField,
1688     shape: Shape,
1689     prefix_max_width: usize,
1690 ) -> Option<String> {
1691     if contains_skip(&field.attrs) {
1692         return Some(context.snippet(field.span()).to_owned());
1693     }
1694     let mut attrs_str = field.attrs.rewrite(context, shape)?;
1695     if !attrs_str.is_empty() {
1696         attrs_str.push_str(&shape.indent.to_string_with_newline(context.config));
1697     };
1698     let name = context.snippet(field.ident.span);
1699     if field.is_shorthand {
1700         Some(attrs_str + name)
1701     } else {
1702         let mut separator = String::from(struct_lit_field_separator(context.config));
1703         for _ in 0..prefix_max_width.saturating_sub(name.len()) {
1704             separator.push(' ');
1705         }
1706         let overhead = name.len() + separator.len();
1707         let expr_shape = shape.offset_left(overhead)?;
1708         let expr = field.expr.rewrite(context, expr_shape);
1709
1710         match expr {
1711             Some(ref e) if e.as_str() == name && context.config.use_field_init_shorthand() => {
1712                 Some(attrs_str + name)
1713             }
1714             Some(e) => Some(format!("{}{}{}{}", attrs_str, name, separator, e)),
1715             None => {
1716                 let expr_offset = shape.indent.block_indent(context.config);
1717                 let expr = field
1718                     .expr
1719                     .rewrite(context, Shape::indented(expr_offset, context.config));
1720                 expr.map(|s| {
1721                     format!(
1722                         "{}{}:\n{}{}",
1723                         attrs_str,
1724                         name,
1725                         expr_offset.to_string(context.config),
1726                         s
1727                     )
1728                 })
1729             }
1730         }
1731     }
1732 }
1733
1734 fn rewrite_tuple_in_visual_indent_style<'a, T: 'a + IntoOverflowableItem<'a>>(
1735     context: &RewriteContext<'_>,
1736     mut items: impl Iterator<Item = &'a T>,
1737     span: Span,
1738     shape: Shape,
1739     is_singleton_tuple: bool,
1740 ) -> Option<String> {
1741     // In case of length 1, need a trailing comma
1742     debug!("rewrite_tuple_in_visual_indent_style {:?}", shape);
1743     if is_singleton_tuple {
1744         // 3 = "(" + ",)"
1745         let nested_shape = shape.sub_width(3)?.visual_indent(1);
1746         return items
1747             .next()
1748             .unwrap()
1749             .rewrite(context, nested_shape)
1750             .map(|s| format!("({},)", s));
1751     }
1752
1753     let list_lo = context.snippet_provider.span_after(span, "(");
1754     let nested_shape = shape.sub_width(2)?.visual_indent(1);
1755     let items = itemize_list(
1756         context.snippet_provider,
1757         items,
1758         ")",
1759         ",",
1760         |item| item.span().lo(),
1761         |item| item.span().hi(),
1762         |item| item.rewrite(context, nested_shape),
1763         list_lo,
1764         span.hi() - BytePos(1),
1765         false,
1766     );
1767     let item_vec: Vec<_> = items.collect();
1768     let tactic = definitive_tactic(
1769         &item_vec,
1770         ListTactic::HorizontalVertical,
1771         Separator::Comma,
1772         nested_shape.width,
1773     );
1774     let fmt = ListFormatting::new(nested_shape, context.config)
1775         .tactic(tactic)
1776         .ends_with_newline(false);
1777     let list_str = write_list(&item_vec, &fmt)?;
1778
1779     Some(format!("({})", list_str))
1780 }
1781
1782 pub(crate) fn rewrite_tuple<'a, T: 'a + IntoOverflowableItem<'a>>(
1783     context: &'a RewriteContext<'_>,
1784     items: impl Iterator<Item = &'a T>,
1785     span: Span,
1786     shape: Shape,
1787     is_singleton_tuple: bool,
1788 ) -> Option<String> {
1789     debug!("rewrite_tuple {:?}", shape);
1790     if context.use_block_indent() {
1791         // We use the same rule as function calls for rewriting tuples.
1792         let force_tactic = if context.inside_macro() {
1793             if span_ends_with_comma(context, span) {
1794                 Some(SeparatorTactic::Always)
1795             } else {
1796                 Some(SeparatorTactic::Never)
1797             }
1798         } else if is_singleton_tuple {
1799             Some(SeparatorTactic::Always)
1800         } else {
1801             None
1802         };
1803         overflow::rewrite_with_parens(
1804             context,
1805             "",
1806             items,
1807             shape,
1808             span,
1809             context.config.fn_call_width(),
1810             force_tactic,
1811         )
1812     } else {
1813         rewrite_tuple_in_visual_indent_style(context, items, span, shape, is_singleton_tuple)
1814     }
1815 }
1816
1817 pub(crate) fn rewrite_unary_prefix<R: Rewrite>(
1818     context: &RewriteContext<'_>,
1819     prefix: &str,
1820     rewrite: &R,
1821     shape: Shape,
1822 ) -> Option<String> {
1823     rewrite
1824         .rewrite(context, shape.offset_left(prefix.len())?)
1825         .map(|r| format!("{}{}", prefix, r))
1826 }
1827
1828 // FIXME: this is probably not correct for multi-line Rewrites. we should
1829 // subtract suffix.len() from the last line budget, not the first!
1830 pub(crate) fn rewrite_unary_suffix<R: Rewrite>(
1831     context: &RewriteContext<'_>,
1832     suffix: &str,
1833     rewrite: &R,
1834     shape: Shape,
1835 ) -> Option<String> {
1836     rewrite
1837         .rewrite(context, shape.sub_width(suffix.len())?)
1838         .map(|mut r| {
1839             r.push_str(suffix);
1840             r
1841         })
1842 }
1843
1844 fn rewrite_unary_op(
1845     context: &RewriteContext<'_>,
1846     op: ast::UnOp,
1847     expr: &ast::Expr,
1848     shape: Shape,
1849 ) -> Option<String> {
1850     // For some reason, an UnOp is not spanned like BinOp!
1851     rewrite_unary_prefix(context, ast::UnOp::to_string(op), expr, shape)
1852 }
1853
1854 pub(crate) enum RhsAssignKind<'ast> {
1855     Expr(&'ast ast::ExprKind, Span),
1856     Bounds,
1857     Ty,
1858 }
1859
1860 impl<'ast> RhsAssignKind<'ast> {
1861     // TODO(calebcartwright)
1862     // Preemptive addition for handling RHS with chains, not yet utilized.
1863     // It may make more sense to construct the chain first and then check
1864     // whether there are actually chain elements.
1865     #[allow(dead_code)]
1866     fn is_chain(&self) -> bool {
1867         match self {
1868             RhsAssignKind::Expr(kind, _) => {
1869                 matches!(
1870                     kind,
1871                     ast::ExprKind::Try(..)
1872                         | ast::ExprKind::Field(..)
1873                         | ast::ExprKind::MethodCall(..)
1874                         | ast::ExprKind::Await(_)
1875                 )
1876             }
1877             _ => false,
1878         }
1879     }
1880 }
1881
1882 fn rewrite_assignment(
1883     context: &RewriteContext<'_>,
1884     lhs: &ast::Expr,
1885     rhs: &ast::Expr,
1886     op: Option<&ast::BinOp>,
1887     shape: Shape,
1888 ) -> Option<String> {
1889     let operator_str = match op {
1890         Some(op) => context.snippet(op.span),
1891         None => "=",
1892     };
1893
1894     // 1 = space between lhs and operator.
1895     let lhs_shape = shape.sub_width(operator_str.len() + 1)?;
1896     let lhs_str = format!("{} {}", lhs.rewrite(context, lhs_shape)?, operator_str);
1897
1898     rewrite_assign_rhs(
1899         context,
1900         lhs_str,
1901         rhs,
1902         &RhsAssignKind::Expr(&rhs.kind, rhs.span),
1903         shape,
1904     )
1905 }
1906
1907 /// Controls where to put the rhs.
1908 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
1909 pub(crate) enum RhsTactics {
1910     /// Use heuristics.
1911     Default,
1912     /// Put the rhs on the next line if it uses multiple line, without extra indentation.
1913     ForceNextLineWithoutIndent,
1914     /// Allow overflowing max width if neither `Default` nor `ForceNextLineWithoutIndent`
1915     /// did not work.
1916     AllowOverflow,
1917 }
1918
1919 // The left hand side must contain everything up to, and including, the
1920 // assignment operator.
1921 pub(crate) fn rewrite_assign_rhs<S: Into<String>, R: Rewrite>(
1922     context: &RewriteContext<'_>,
1923     lhs: S,
1924     ex: &R,
1925     rhs_kind: &RhsAssignKind<'_>,
1926     shape: Shape,
1927 ) -> Option<String> {
1928     rewrite_assign_rhs_with(context, lhs, ex, shape, rhs_kind, RhsTactics::Default)
1929 }
1930
1931 pub(crate) fn rewrite_assign_rhs_expr<R: Rewrite>(
1932     context: &RewriteContext<'_>,
1933     lhs: &str,
1934     ex: &R,
1935     shape: Shape,
1936     rhs_kind: &RhsAssignKind<'_>,
1937     rhs_tactics: RhsTactics,
1938 ) -> Option<String> {
1939     let last_line_width = last_line_width(lhs).saturating_sub(if lhs.contains('\n') {
1940         shape.indent.width()
1941     } else {
1942         0
1943     });
1944     // 1 = space between operator and rhs.
1945     let orig_shape = shape.offset_left(last_line_width + 1).unwrap_or(Shape {
1946         width: 0,
1947         offset: shape.offset + last_line_width + 1,
1948         ..shape
1949     });
1950     let has_rhs_comment = if let Some(offset) = lhs.find_last_uncommented("=") {
1951         lhs.trim_end().len() > offset + 1
1952     } else {
1953         false
1954     };
1955
1956     choose_rhs(
1957         context,
1958         ex,
1959         orig_shape,
1960         ex.rewrite(context, orig_shape),
1961         rhs_kind,
1962         rhs_tactics,
1963         has_rhs_comment,
1964     )
1965 }
1966
1967 pub(crate) fn rewrite_assign_rhs_with<S: Into<String>, R: Rewrite>(
1968     context: &RewriteContext<'_>,
1969     lhs: S,
1970     ex: &R,
1971     shape: Shape,
1972     rhs_kind: &RhsAssignKind<'_>,
1973     rhs_tactics: RhsTactics,
1974 ) -> Option<String> {
1975     let lhs = lhs.into();
1976     let rhs = rewrite_assign_rhs_expr(context, &lhs, ex, shape, rhs_kind, rhs_tactics)?;
1977     Some(lhs + &rhs)
1978 }
1979
1980 pub(crate) fn rewrite_assign_rhs_with_comments<S: Into<String>, R: Rewrite>(
1981     context: &RewriteContext<'_>,
1982     lhs: S,
1983     ex: &R,
1984     shape: Shape,
1985     rhs_kind: &RhsAssignKind<'_>,
1986     rhs_tactics: RhsTactics,
1987     between_span: Span,
1988     allow_extend: bool,
1989 ) -> Option<String> {
1990     let lhs = lhs.into();
1991     let contains_comment = contains_comment(context.snippet(between_span));
1992     let shape = if contains_comment {
1993         shape.block_left(context.config.tab_spaces())?
1994     } else {
1995         shape
1996     };
1997     let rhs = rewrite_assign_rhs_expr(context, &lhs, ex, shape, rhs_kind, rhs_tactics)?;
1998
1999     if contains_comment {
2000         let rhs = rhs.trim_start();
2001         combine_strs_with_missing_comments(context, &lhs, rhs, between_span, shape, allow_extend)
2002     } else {
2003         Some(lhs + &rhs)
2004     }
2005 }
2006
2007 fn choose_rhs<R: Rewrite>(
2008     context: &RewriteContext<'_>,
2009     expr: &R,
2010     shape: Shape,
2011     orig_rhs: Option<String>,
2012     _rhs_kind: &RhsAssignKind<'_>,
2013     rhs_tactics: RhsTactics,
2014     has_rhs_comment: bool,
2015 ) -> Option<String> {
2016     match orig_rhs {
2017         Some(ref new_str) if new_str.is_empty() => Some(String::new()),
2018         Some(ref new_str)
2019             if !new_str.contains('\n') && unicode_str_width(new_str) <= shape.width =>
2020         {
2021             Some(format!(" {}", new_str))
2022         }
2023         _ => {
2024             // Expression did not fit on the same line as the identifier.
2025             // Try splitting the line and see if that works better.
2026             let new_shape = shape_from_rhs_tactic(context, shape, rhs_tactics)?;
2027             let new_rhs = expr.rewrite(context, new_shape);
2028             let new_indent_str = &shape
2029                 .indent
2030                 .block_indent(context.config)
2031                 .to_string_with_newline(context.config);
2032             let before_space_str = if has_rhs_comment { "" } else { " " };
2033
2034             match (orig_rhs, new_rhs) {
2035                 (Some(ref orig_rhs), Some(ref new_rhs))
2036                     if wrap_str(new_rhs.clone(), context.config.max_width(), new_shape)
2037                         .is_none() =>
2038                 {
2039                     Some(format!("{}{}", before_space_str, orig_rhs))
2040                 }
2041                 (Some(ref orig_rhs), Some(ref new_rhs))
2042                     if prefer_next_line(orig_rhs, new_rhs, rhs_tactics) =>
2043                 {
2044                     Some(format!("{}{}", new_indent_str, new_rhs))
2045                 }
2046                 (None, Some(ref new_rhs)) => Some(format!("{}{}", new_indent_str, new_rhs)),
2047                 (None, None) if rhs_tactics == RhsTactics::AllowOverflow => {
2048                     let shape = shape.infinite_width();
2049                     expr.rewrite(context, shape)
2050                         .map(|s| format!("{}{}", before_space_str, s))
2051                 }
2052                 (None, None) => None,
2053                 (Some(orig_rhs), _) => Some(format!("{}{}", before_space_str, orig_rhs)),
2054             }
2055         }
2056     }
2057 }
2058
2059 fn shape_from_rhs_tactic(
2060     context: &RewriteContext<'_>,
2061     shape: Shape,
2062     rhs_tactic: RhsTactics,
2063 ) -> Option<Shape> {
2064     match rhs_tactic {
2065         RhsTactics::ForceNextLineWithoutIndent => shape
2066             .with_max_width(context.config)
2067             .sub_width(shape.indent.width()),
2068         RhsTactics::Default | RhsTactics::AllowOverflow => {
2069             Shape::indented(shape.indent.block_indent(context.config), context.config)
2070                 .sub_width(shape.rhs_overhead(context.config))
2071         }
2072     }
2073 }
2074
2075 /// Returns true if formatting next_line_rhs is better on a new line when compared to the
2076 /// original's line formatting.
2077 ///
2078 /// It is considered better if:
2079 /// 1. the tactic is ForceNextLineWithoutIndent
2080 /// 2. next_line_rhs doesn't have newlines
2081 /// 3. the original line has more newlines than next_line_rhs
2082 /// 4. the original formatting of the first line ends with `(`, `{`, or `[` and next_line_rhs
2083 ///    doesn't
2084 pub(crate) fn prefer_next_line(
2085     orig_rhs: &str,
2086     next_line_rhs: &str,
2087     rhs_tactics: RhsTactics,
2088 ) -> bool {
2089     rhs_tactics == RhsTactics::ForceNextLineWithoutIndent
2090         || !next_line_rhs.contains('\n')
2091         || count_newlines(orig_rhs) > count_newlines(next_line_rhs) + 1
2092         || first_line_ends_with(orig_rhs, '(') && !first_line_ends_with(next_line_rhs, '(')
2093         || first_line_ends_with(orig_rhs, '{') && !first_line_ends_with(next_line_rhs, '{')
2094         || first_line_ends_with(orig_rhs, '[') && !first_line_ends_with(next_line_rhs, '[')
2095 }
2096
2097 fn rewrite_expr_addrof(
2098     context: &RewriteContext<'_>,
2099     borrow_kind: ast::BorrowKind,
2100     mutability: ast::Mutability,
2101     expr: &ast::Expr,
2102     shape: Shape,
2103 ) -> Option<String> {
2104     let operator_str = match (mutability, borrow_kind) {
2105         (ast::Mutability::Not, ast::BorrowKind::Ref) => "&",
2106         (ast::Mutability::Not, ast::BorrowKind::Raw) => "&raw const ",
2107         (ast::Mutability::Mut, ast::BorrowKind::Ref) => "&mut ",
2108         (ast::Mutability::Mut, ast::BorrowKind::Raw) => "&raw mut ",
2109     };
2110     rewrite_unary_prefix(context, operator_str, expr, shape)
2111 }
2112
2113 pub(crate) fn is_method_call(expr: &ast::Expr) -> bool {
2114     match expr.kind {
2115         ast::ExprKind::MethodCall(..) => true,
2116         ast::ExprKind::AddrOf(_, _, ref expr)
2117         | ast::ExprKind::Box(ref expr)
2118         | ast::ExprKind::Cast(ref expr, _)
2119         | ast::ExprKind::Try(ref expr)
2120         | ast::ExprKind::Unary(_, ref expr) => is_method_call(expr),
2121         _ => false,
2122     }
2123 }
2124
2125 #[cfg(test)]
2126 mod test {
2127     use super::last_line_offsetted;
2128
2129     #[test]
2130     fn test_last_line_offsetted() {
2131         let lines = "one\n    two";
2132         assert_eq!(last_line_offsetted(2, lines), true);
2133         assert_eq!(last_line_offsetted(4, lines), false);
2134         assert_eq!(last_line_offsetted(6, lines), false);
2135
2136         let lines = "one    two";
2137         assert_eq!(last_line_offsetted(2, lines), false);
2138         assert_eq!(last_line_offsetted(0, lines), false);
2139
2140         let lines = "\ntwo";
2141         assert_eq!(last_line_offsetted(2, lines), false);
2142         assert_eq!(last_line_offsetted(0, lines), false);
2143
2144         let lines = "one\n    two      three";
2145         assert_eq!(last_line_offsetted(2, lines), true);
2146         let lines = "one\n two      three";
2147         assert_eq!(last_line_offsetted(2, lines), false);
2148     }
2149 }