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