]> git.lizzy.rs Git - rust.git/blob - src/overflow.rs
Release v1.4.2
[rust.git] / src / overflow.rs
1 //! Rewrite a list some items with overflow.
2
3 use std::cmp::min;
4
5 use itertools::Itertools;
6 use syntax::parse::token::DelimToken;
7 use syntax::source_map::Span;
8 use syntax::{ast, ptr};
9
10 use crate::closures;
11 use crate::config::lists::*;
12 use crate::config::Version;
13 use crate::expr::{
14     can_be_overflowed_expr, is_every_expr_simple, is_method_call, is_nested_call, is_simple_expr,
15     rewrite_cond,
16 };
17 use crate::lists::{
18     definitive_tactic, itemize_list, write_list, ListFormatting, ListItem, Separator,
19 };
20 use crate::macros::MacroArg;
21 use crate::patterns::{can_be_overflowed_pat, TuplePatField};
22 use crate::rewrite::{Rewrite, RewriteContext};
23 use crate::shape::Shape;
24 use crate::source_map::SpanUtils;
25 use crate::spanned::Spanned;
26 use crate::types::{can_be_overflowed_type, SegmentParam};
27 use crate::utils::{count_newlines, extra_offset, first_line_width, last_line_width, mk_sp};
28
29 const SHORT_ITEM_THRESHOLD: usize = 10;
30
31 /// A list of `format!`-like macros, that take a long format string and a list of arguments to
32 /// format.
33 ///
34 /// Organized as a list of `(&str, usize)` tuples, giving the name of the macro and the number of
35 /// arguments before the format string (none for `format!("format", ...)`, one for `assert!(result,
36 /// "format", ...)`, two for `assert_eq!(left, right, "format", ...)`).
37 const SPECIAL_MACRO_WHITELIST: &[(&str, usize)] = &[
38     // format! like macros
39     // From the Rust Standard Library.
40     ("eprint!", 0),
41     ("eprintln!", 0),
42     ("format!", 0),
43     ("format_args!", 0),
44     ("print!", 0),
45     ("println!", 0),
46     ("panic!", 0),
47     ("unreachable!", 0),
48     // From the `log` crate.
49     ("debug!", 0),
50     ("error!", 0),
51     ("info!", 0),
52     ("warn!", 0),
53     // write! like macros
54     ("assert!", 1),
55     ("debug_assert!", 1),
56     ("write!", 1),
57     ("writeln!", 1),
58     // assert_eq! like macros
59     ("assert_eq!", 2),
60     ("assert_ne!", 2),
61     ("debug_assert_eq!", 2),
62     ("debug_assert_ne!", 2),
63 ];
64
65 const SPECIAL_ATTR_WHITELIST: &[(&str, usize)] = &[
66     // From the `failure` crate.
67     ("fail", 0),
68 ];
69
70 #[derive(Debug)]
71 pub(crate) enum OverflowableItem<'a> {
72     Expr(&'a ast::Expr),
73     GenericParam(&'a ast::GenericParam),
74     MacroArg(&'a MacroArg),
75     NestedMetaItem(&'a ast::NestedMetaItem),
76     SegmentParam(&'a SegmentParam<'a>),
77     StructField(&'a ast::StructField),
78     TuplePatField(&'a TuplePatField<'a>),
79     Ty(&'a ast::Ty),
80 }
81
82 impl<'a> Rewrite for OverflowableItem<'a> {
83     fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
84         self.map(|item| item.rewrite(context, shape))
85     }
86 }
87
88 impl<'a> Spanned for OverflowableItem<'a> {
89     fn span(&self) -> Span {
90         self.map(|item| item.span())
91     }
92 }
93
94 impl<'a> OverflowableItem<'a> {
95     fn has_attrs(&self) -> bool {
96         match self {
97             OverflowableItem::Expr(ast::Expr { attrs, .. })
98             | OverflowableItem::GenericParam(ast::GenericParam { attrs, .. }) => !attrs.is_empty(),
99             OverflowableItem::StructField(ast::StructField { attrs, .. }) => !attrs.is_empty(),
100             OverflowableItem::MacroArg(MacroArg::Expr(expr)) => !expr.attrs.is_empty(),
101             OverflowableItem::MacroArg(MacroArg::Item(item)) => !item.attrs.is_empty(),
102             _ => false,
103         }
104     }
105
106     pub(crate) fn map<F, T>(&self, f: F) -> T
107     where
108         F: Fn(&dyn IntoOverflowableItem<'a>) -> T,
109     {
110         match self {
111             OverflowableItem::Expr(expr) => f(*expr),
112             OverflowableItem::GenericParam(gp) => f(*gp),
113             OverflowableItem::MacroArg(macro_arg) => f(*macro_arg),
114             OverflowableItem::NestedMetaItem(nmi) => f(*nmi),
115             OverflowableItem::SegmentParam(sp) => f(*sp),
116             OverflowableItem::StructField(sf) => f(*sf),
117             OverflowableItem::TuplePatField(pat) => f(*pat),
118             OverflowableItem::Ty(ty) => f(*ty),
119         }
120     }
121
122     pub(crate) fn is_simple(&self) -> bool {
123         match self {
124             OverflowableItem::Expr(expr) => is_simple_expr(expr),
125             OverflowableItem::MacroArg(MacroArg::Expr(expr)) => is_simple_expr(expr),
126             OverflowableItem::NestedMetaItem(nested_meta_item) => match nested_meta_item {
127                 ast::NestedMetaItem::Literal(..) => true,
128                 ast::NestedMetaItem::MetaItem(ref meta_item) => match meta_item.node {
129                     ast::MetaItemKind::Word => true,
130                     _ => false,
131                 },
132             },
133             _ => false,
134         }
135     }
136
137     pub(crate) fn is_expr(&self) -> bool {
138         match self {
139             OverflowableItem::Expr(..) => true,
140             OverflowableItem::MacroArg(MacroArg::Expr(..)) => true,
141             _ => false,
142         }
143     }
144
145     pub(crate) fn is_nested_call(&self) -> bool {
146         match self {
147             OverflowableItem::Expr(expr) => is_nested_call(expr),
148             OverflowableItem::MacroArg(MacroArg::Expr(expr)) => is_nested_call(expr),
149             _ => false,
150         }
151     }
152
153     pub(crate) fn to_expr(&self) -> Option<&'a ast::Expr> {
154         match self {
155             OverflowableItem::Expr(expr) => Some(expr),
156             OverflowableItem::MacroArg(macro_arg) => match macro_arg {
157                 MacroArg::Expr(ref expr) => Some(expr),
158                 _ => None,
159             },
160             _ => None,
161         }
162     }
163
164     pub(crate) fn can_be_overflowed(&self, context: &RewriteContext<'_>, len: usize) -> bool {
165         match self {
166             OverflowableItem::Expr(expr) => can_be_overflowed_expr(context, expr, len),
167             OverflowableItem::MacroArg(macro_arg) => match macro_arg {
168                 MacroArg::Expr(ref expr) => can_be_overflowed_expr(context, expr, len),
169                 MacroArg::Ty(ref ty) => can_be_overflowed_type(context, ty, len),
170                 MacroArg::Pat(..) => false,
171                 MacroArg::Item(..) => len == 1,
172                 MacroArg::Keyword(..) => false,
173             },
174             OverflowableItem::NestedMetaItem(nested_meta_item) if len == 1 => {
175                 match nested_meta_item {
176                     ast::NestedMetaItem::Literal(..) => false,
177                     ast::NestedMetaItem::MetaItem(..) => true,
178                 }
179             }
180             OverflowableItem::SegmentParam(seg) => match seg {
181                 SegmentParam::Type(ty) => can_be_overflowed_type(context, ty, len),
182                 _ => false,
183             },
184             OverflowableItem::TuplePatField(pat) => can_be_overflowed_pat(context, pat, len),
185             OverflowableItem::Ty(ty) => can_be_overflowed_type(context, ty, len),
186             _ => false,
187         }
188     }
189
190     fn whitelist(&self) -> &'static [(&'static str, usize)] {
191         match self {
192             OverflowableItem::MacroArg(..) => SPECIAL_MACRO_WHITELIST,
193             OverflowableItem::NestedMetaItem(..) => SPECIAL_ATTR_WHITELIST,
194             _ => &[],
195         }
196     }
197 }
198
199 pub(crate) trait IntoOverflowableItem<'a>: Rewrite + Spanned {
200     fn into_overflowable_item(&'a self) -> OverflowableItem<'a>;
201 }
202
203 impl<'a, T: 'a + IntoOverflowableItem<'a>> IntoOverflowableItem<'a> for ptr::P<T> {
204     fn into_overflowable_item(&'a self) -> OverflowableItem<'a> {
205         (**self).into_overflowable_item()
206     }
207 }
208
209 macro_rules! impl_into_overflowable_item_for_ast_node {
210     ($($ast_node:ident),*) => {
211         $(
212             impl<'a> IntoOverflowableItem<'a> for ast::$ast_node {
213                 fn into_overflowable_item(&'a self) -> OverflowableItem<'a> {
214                     OverflowableItem::$ast_node(self)
215                 }
216             }
217         )*
218     }
219 }
220
221 macro_rules! impl_into_overflowable_item_for_rustfmt_types {
222     ([$($ty:ident),*], [$($ty_with_lifetime:ident),*]) => {
223         $(
224             impl<'a> IntoOverflowableItem<'a> for $ty {
225                 fn into_overflowable_item(&'a self) -> OverflowableItem<'a> {
226                     OverflowableItem::$ty(self)
227                 }
228             }
229         )*
230         $(
231             impl<'a> IntoOverflowableItem<'a> for $ty_with_lifetime<'a> {
232                 fn into_overflowable_item(&'a self) -> OverflowableItem<'a> {
233                     OverflowableItem::$ty_with_lifetime(self)
234                 }
235             }
236         )*
237     }
238 }
239
240 impl_into_overflowable_item_for_ast_node!(Expr, GenericParam, NestedMetaItem, StructField, Ty);
241 impl_into_overflowable_item_for_rustfmt_types!([MacroArg], [SegmentParam, TuplePatField]);
242
243 pub(crate) fn into_overflowable_list<'a, T>(
244     iter: impl Iterator<Item = &'a T>,
245 ) -> impl Iterator<Item = OverflowableItem<'a>>
246 where
247     T: 'a + IntoOverflowableItem<'a>,
248 {
249     iter.map(|x| IntoOverflowableItem::into_overflowable_item(x))
250 }
251
252 pub(crate) fn rewrite_with_parens<'a, T: 'a + IntoOverflowableItem<'a>>(
253     context: &'a RewriteContext<'_>,
254     ident: &'a str,
255     items: impl Iterator<Item = &'a T>,
256     shape: Shape,
257     span: Span,
258     item_max_width: usize,
259     force_separator_tactic: Option<SeparatorTactic>,
260 ) -> Option<String> {
261     Context::new(
262         context,
263         items,
264         ident,
265         shape,
266         span,
267         "(",
268         ")",
269         item_max_width,
270         force_separator_tactic,
271         None,
272     )
273     .rewrite(shape)
274 }
275
276 pub(crate) fn rewrite_with_angle_brackets<'a, T: 'a + IntoOverflowableItem<'a>>(
277     context: &'a RewriteContext<'_>,
278     ident: &'a str,
279     items: impl Iterator<Item = &'a T>,
280     shape: Shape,
281     span: Span,
282 ) -> Option<String> {
283     Context::new(
284         context,
285         items,
286         ident,
287         shape,
288         span,
289         "<",
290         ">",
291         context.config.max_width(),
292         None,
293         None,
294     )
295     .rewrite(shape)
296 }
297
298 pub(crate) fn rewrite_with_square_brackets<'a, T: 'a + IntoOverflowableItem<'a>>(
299     context: &'a RewriteContext<'_>,
300     name: &'a str,
301     items: impl Iterator<Item = &'a T>,
302     shape: Shape,
303     span: Span,
304     force_separator_tactic: Option<SeparatorTactic>,
305     delim_token: Option<DelimToken>,
306 ) -> Option<String> {
307     let (lhs, rhs) = match delim_token {
308         Some(DelimToken::Paren) => ("(", ")"),
309         Some(DelimToken::Brace) => ("{", "}"),
310         _ => ("[", "]"),
311     };
312     Context::new(
313         context,
314         items,
315         name,
316         shape,
317         span,
318         lhs,
319         rhs,
320         context.config.width_heuristics().array_width,
321         force_separator_tactic,
322         Some(("[", "]")),
323     )
324     .rewrite(shape)
325 }
326
327 struct Context<'a> {
328     context: &'a RewriteContext<'a>,
329     items: Vec<OverflowableItem<'a>>,
330     ident: &'a str,
331     prefix: &'static str,
332     suffix: &'static str,
333     one_line_shape: Shape,
334     nested_shape: Shape,
335     span: Span,
336     item_max_width: usize,
337     one_line_width: usize,
338     force_separator_tactic: Option<SeparatorTactic>,
339     custom_delims: Option<(&'a str, &'a str)>,
340 }
341
342 impl<'a> Context<'a> {
343     fn new<T: 'a + IntoOverflowableItem<'a>>(
344         context: &'a RewriteContext<'_>,
345         items: impl Iterator<Item = &'a T>,
346         ident: &'a str,
347         shape: Shape,
348         span: Span,
349         prefix: &'static str,
350         suffix: &'static str,
351         item_max_width: usize,
352         force_separator_tactic: Option<SeparatorTactic>,
353         custom_delims: Option<(&'a str, &'a str)>,
354     ) -> Context<'a> {
355         let used_width = extra_offset(ident, shape);
356         // 1 = `()`
357         let one_line_width = shape.width.saturating_sub(used_width + 2);
358
359         // 1 = "(" or ")"
360         let one_line_shape = shape
361             .offset_left(last_line_width(ident) + 1)
362             .and_then(|shape| shape.sub_width(1))
363             .unwrap_or(Shape { width: 0, ..shape });
364         let nested_shape = shape_from_indent_style(context, shape, used_width + 2, used_width + 1);
365         Context {
366             context,
367             items: into_overflowable_list(items).collect(),
368             ident,
369             one_line_shape,
370             nested_shape,
371             span,
372             prefix,
373             suffix,
374             item_max_width,
375             one_line_width,
376             force_separator_tactic,
377             custom_delims,
378         }
379     }
380
381     fn last_item(&self) -> Option<&OverflowableItem<'_>> {
382         self.items.last()
383     }
384
385     fn items_span(&self) -> Span {
386         let span_lo = self
387             .context
388             .snippet_provider
389             .span_after(self.span, self.prefix);
390         mk_sp(span_lo, self.span.hi())
391     }
392
393     fn rewrite_last_item_with_overflow(
394         &self,
395         last_list_item: &mut ListItem,
396         shape: Shape,
397     ) -> Option<String> {
398         let last_item = self.last_item()?;
399         let rewrite = match last_item {
400             OverflowableItem::Expr(ref expr) => {
401                 match expr.node {
402                     // When overflowing the closure which consists of a single control flow
403                     // expression, force to use block if its condition uses multi line.
404                     ast::ExprKind::Closure(..) => {
405                         // If the argument consists of multiple closures, we do not overflow
406                         // the last closure.
407                         if closures::args_have_many_closure(&self.items) {
408                             None
409                         } else {
410                             closures::rewrite_last_closure(self.context, expr, shape)
411                         }
412                     }
413
414                     // When overflowing the expressions which consists of a control flow
415                     // expression, avoid condition to use multi line.
416                     ast::ExprKind::If(..)
417                     | ast::ExprKind::ForLoop(..)
418                     | ast::ExprKind::Loop(..)
419                     | ast::ExprKind::While(..)
420                     | ast::ExprKind::Match(..) => {
421                         let multi_line = rewrite_cond(self.context, expr, shape)
422                             .map_or(false, |cond| cond.contains('\n'));
423
424                         if multi_line {
425                             None
426                         } else {
427                             expr.rewrite(self.context, shape)
428                         }
429                     }
430
431                     _ => expr.rewrite(self.context, shape),
432                 }
433             }
434             item => item.rewrite(self.context, shape),
435         };
436
437         if let Some(rewrite) = rewrite {
438             // splitn(2, *).next().unwrap() is always safe.
439             let rewrite_first_line = Some(rewrite.splitn(2, '\n').next().unwrap().to_owned());
440             last_list_item.item = rewrite_first_line;
441             Some(rewrite)
442         } else {
443             None
444         }
445     }
446
447     fn default_tactic(&self, list_items: &[ListItem]) -> DefinitiveListTactic {
448         definitive_tactic(
449             list_items,
450             ListTactic::LimitedHorizontalVertical(self.item_max_width),
451             Separator::Comma,
452             self.one_line_width,
453         )
454     }
455
456     fn try_overflow_last_item(&self, list_items: &mut Vec<ListItem>) -> DefinitiveListTactic {
457         // 1 = "("
458         let combine_arg_with_callee = self.items.len() == 1
459             && self.items[0].is_expr()
460             && !self.items[0].has_attrs()
461             && self.ident.len() < self.context.config.tab_spaces();
462         let overflow_last = combine_arg_with_callee || can_be_overflowed(self.context, &self.items);
463
464         // Replace the last item with its first line to see if it fits with
465         // first arguments.
466         let placeholder = if overflow_last {
467             let old_value = *self.context.force_one_line_chain.borrow();
468             match self.last_item() {
469                 Some(OverflowableItem::Expr(expr))
470                     if !combine_arg_with_callee && is_method_call(expr) =>
471                 {
472                     self.context.force_one_line_chain.replace(true);
473                 }
474                 Some(OverflowableItem::MacroArg(MacroArg::Expr(expr)))
475                     if !combine_arg_with_callee
476                         && is_method_call(expr)
477                         && self.context.config.version() == Version::Two =>
478                 {
479                     self.context.force_one_line_chain.replace(true);
480                 }
481                 _ => (),
482             }
483             let result = last_item_shape(
484                 &self.items,
485                 list_items,
486                 self.one_line_shape,
487                 self.item_max_width,
488             )
489             .and_then(|arg_shape| {
490                 self.rewrite_last_item_with_overflow(
491                     &mut list_items[self.items.len() - 1],
492                     arg_shape,
493                 )
494             });
495             self.context.force_one_line_chain.replace(old_value);
496             result
497         } else {
498             None
499         };
500
501         let mut tactic = definitive_tactic(
502             &*list_items,
503             ListTactic::LimitedHorizontalVertical(self.item_max_width),
504             Separator::Comma,
505             self.one_line_width,
506         );
507
508         // Replace the stub with the full overflowing last argument if the rewrite
509         // succeeded and its first line fits with the other arguments.
510         match (overflow_last, tactic, placeholder) {
511             (true, DefinitiveListTactic::Horizontal, Some(ref overflowed))
512                 if self.items.len() == 1 =>
513             {
514                 // When we are rewriting a nested function call, we restrict the
515                 // budget for the inner function to avoid them being deeply nested.
516                 // However, when the inner function has a prefix or a suffix
517                 // (e.g., `foo() as u32`), this budget reduction may produce poorly
518                 // formatted code, where a prefix or a suffix being left on its own
519                 // line. Here we explicitlly check those cases.
520                 if count_newlines(overflowed) == 1 {
521                     let rw = self
522                         .items
523                         .last()
524                         .and_then(|last_item| last_item.rewrite(self.context, self.nested_shape));
525                     let no_newline = rw.as_ref().map_or(false, |s| !s.contains('\n'));
526                     if no_newline {
527                         list_items[self.items.len() - 1].item = rw;
528                     } else {
529                         list_items[self.items.len() - 1].item = Some(overflowed.to_owned());
530                     }
531                 } else {
532                     list_items[self.items.len() - 1].item = Some(overflowed.to_owned());
533                 }
534             }
535             (true, DefinitiveListTactic::Horizontal, placeholder @ Some(..)) => {
536                 list_items[self.items.len() - 1].item = placeholder;
537             }
538             _ if !self.items.is_empty() => {
539                 list_items[self.items.len() - 1].item = self
540                     .items
541                     .last()
542                     .and_then(|last_item| last_item.rewrite(self.context, self.nested_shape));
543
544                 // Use horizontal layout for a function with a single argument as long as
545                 // everything fits in a single line.
546                 // `self.one_line_width == 0` means vertical layout is forced.
547                 if self.items.len() == 1
548                     && self.one_line_width != 0
549                     && !list_items[0].has_comment()
550                     && !list_items[0].inner_as_ref().contains('\n')
551                     && crate::lists::total_item_width(&list_items[0]) <= self.one_line_width
552                 {
553                     tactic = DefinitiveListTactic::Horizontal;
554                 } else {
555                     tactic = self.default_tactic(list_items);
556
557                     if tactic == DefinitiveListTactic::Vertical {
558                         if let Some((all_simple, num_args_before)) =
559                             maybe_get_args_offset(self.ident, &self.items)
560                         {
561                             let one_line = all_simple
562                                 && definitive_tactic(
563                                     &list_items[..num_args_before],
564                                     ListTactic::HorizontalVertical,
565                                     Separator::Comma,
566                                     self.nested_shape.width,
567                                 ) == DefinitiveListTactic::Horizontal
568                                 && definitive_tactic(
569                                     &list_items[num_args_before + 1..],
570                                     ListTactic::HorizontalVertical,
571                                     Separator::Comma,
572                                     self.nested_shape.width,
573                                 ) == DefinitiveListTactic::Horizontal;
574
575                             if one_line {
576                                 tactic = DefinitiveListTactic::SpecialMacro(num_args_before);
577                             };
578                         } else if is_every_expr_simple(&self.items) && no_long_items(list_items) {
579                             tactic = DefinitiveListTactic::Mixed;
580                         }
581                     }
582                 }
583             }
584             _ => (),
585         }
586
587         tactic
588     }
589
590     fn rewrite_items(&self) -> Option<(bool, String)> {
591         let span = self.items_span();
592         let items = itemize_list(
593             self.context.snippet_provider,
594             self.items.iter(),
595             self.suffix,
596             ",",
597             |item| item.span().lo(),
598             |item| item.span().hi(),
599             |item| item.rewrite(self.context, self.nested_shape),
600             span.lo(),
601             span.hi(),
602             true,
603         );
604         let mut list_items: Vec<_> = items.collect();
605
606         // Try letting the last argument overflow to the next line with block
607         // indentation. If its first line fits on one line with the other arguments,
608         // we format the function arguments horizontally.
609         let tactic = self.try_overflow_last_item(&mut list_items);
610         let trailing_separator = if let Some(tactic) = self.force_separator_tactic {
611             tactic
612         } else if !self.context.use_block_indent() {
613             SeparatorTactic::Never
614         } else {
615             self.context.config.trailing_comma()
616         };
617         let ends_with_newline = match tactic {
618             DefinitiveListTactic::Vertical | DefinitiveListTactic::Mixed => {
619                 self.context.use_block_indent()
620             }
621             _ => false,
622         };
623
624         let fmt = ListFormatting::new(self.nested_shape, self.context.config)
625             .tactic(tactic)
626             .trailing_separator(trailing_separator)
627             .ends_with_newline(ends_with_newline);
628
629         write_list(&list_items, &fmt)
630             .map(|items_str| (tactic == DefinitiveListTactic::Horizontal, items_str))
631     }
632
633     fn wrap_items(&self, items_str: &str, shape: Shape, is_extendable: bool) -> String {
634         let shape = Shape {
635             width: shape.width.saturating_sub(last_line_width(self.ident)),
636             ..shape
637         };
638
639         let (prefix, suffix) = match self.custom_delims {
640             Some((lhs, rhs)) => (lhs, rhs),
641             _ => (self.prefix, self.suffix),
642         };
643
644         let extend_width = if items_str.is_empty() {
645             2
646         } else {
647             first_line_width(items_str) + 1
648         };
649         let nested_indent_str = self
650             .nested_shape
651             .indent
652             .to_string_with_newline(self.context.config);
653         let indent_str = shape
654             .block()
655             .indent
656             .to_string_with_newline(self.context.config);
657         let mut result = String::with_capacity(
658             self.ident.len() + items_str.len() + 2 + indent_str.len() + nested_indent_str.len(),
659         );
660         result.push_str(self.ident);
661         result.push_str(prefix);
662         let force_single_line = if self.context.config.version() == Version::Two {
663             !self.context.use_block_indent() || (is_extendable && extend_width <= shape.width)
664         } else {
665             // 2 = `()`
666             let fits_one_line = items_str.len() + 2 <= shape.width;
667             !self.context.use_block_indent()
668                 || (self.context.inside_macro() && !items_str.contains('\n') && fits_one_line)
669                 || (is_extendable && extend_width <= shape.width)
670         };
671         if force_single_line {
672             result.push_str(items_str);
673         } else {
674             if !items_str.is_empty() {
675                 result.push_str(&nested_indent_str);
676                 result.push_str(items_str);
677             }
678             result.push_str(&indent_str);
679         }
680         result.push_str(suffix);
681         result
682     }
683
684     fn rewrite(&self, shape: Shape) -> Option<String> {
685         let (extendable, items_str) = self.rewrite_items()?;
686
687         // If we are using visual indent style and failed to format, retry with block indent.
688         if !self.context.use_block_indent()
689             && need_block_indent(&items_str, self.nested_shape)
690             && !extendable
691         {
692             self.context.use_block.replace(true);
693             let result = self.rewrite(shape);
694             self.context.use_block.replace(false);
695             return result;
696         }
697
698         Some(self.wrap_items(&items_str, shape, extendable))
699     }
700 }
701
702 fn need_block_indent(s: &str, shape: Shape) -> bool {
703     s.lines().skip(1).any(|s| {
704         s.find(|c| !char::is_whitespace(c))
705             .map_or(false, |w| w + 1 < shape.indent.width())
706     })
707 }
708
709 fn can_be_overflowed(context: &RewriteContext<'_>, items: &[OverflowableItem<'_>]) -> bool {
710     items
711         .last()
712         .map_or(false, |x| x.can_be_overflowed(context, items.len()))
713 }
714
715 /// Returns a shape for the last argument which is going to be overflowed.
716 fn last_item_shape(
717     lists: &[OverflowableItem<'_>],
718     items: &[ListItem],
719     shape: Shape,
720     args_max_width: usize,
721 ) -> Option<Shape> {
722     if items.len() == 1 && !lists.get(0)?.is_nested_call() {
723         return Some(shape);
724     }
725     let offset = items
726         .iter()
727         .dropping_back(1)
728         .map(|i| {
729             // 2 = ", "
730             2 + i.inner_as_ref().len()
731         })
732         .sum();
733     Shape {
734         width: min(args_max_width, shape.width),
735         ..shape
736     }
737     .offset_left(offset)
738 }
739
740 fn shape_from_indent_style(
741     context: &RewriteContext<'_>,
742     shape: Shape,
743     overhead: usize,
744     offset: usize,
745 ) -> Shape {
746     let (shape, overhead) = if context.use_block_indent() {
747         let shape = shape
748             .block()
749             .block_indent(context.config.tab_spaces())
750             .with_max_width(context.config);
751         (shape, 1) // 1 = ","
752     } else {
753         (shape.visual_indent(offset), overhead)
754     };
755     Shape {
756         width: shape.width.saturating_sub(overhead),
757         ..shape
758     }
759 }
760
761 fn no_long_items(list: &[ListItem]) -> bool {
762     list.iter()
763         .all(|item| item.inner_as_ref().len() <= SHORT_ITEM_THRESHOLD)
764 }
765
766 /// In case special-case style is required, returns an offset from which we start horizontal layout.
767 pub(crate) fn maybe_get_args_offset(
768     callee_str: &str,
769     args: &[OverflowableItem<'_>],
770 ) -> Option<(bool, usize)> {
771     if let Some(&(_, num_args_before)) = args
772         .get(0)?
773         .whitelist()
774         .iter()
775         .find(|&&(s, _)| s == callee_str)
776     {
777         let all_simple = args.len() > num_args_before
778             && is_every_expr_simple(&args[0..num_args_before])
779             && is_every_expr_simple(&args[num_args_before + 1..]);
780
781         Some((all_simple, num_args_before))
782     } else {
783         None
784     }
785 }