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