rustfmt_nightly/
overflow.rs

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