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