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