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