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