rustfmt_nightly/
items.rs

1// Formatting top-level items - functions, structs, enums, traits, impls.
2
3use std::borrow::Cow;
4use std::cmp::{Ordering, max, min};
5
6use regex::Regex;
7use rustc_ast::visit;
8use rustc_ast::{ast, ptr};
9use rustc_span::{BytePos, DUMMY_SP, Ident, Span, symbol};
10use tracing::debug;
11
12use crate::attr::filter_inline_attrs;
13use crate::comment::{
14    FindUncommented, combine_strs_with_missing_comments, contains_comment, is_last_comment_block,
15    recover_comment_removed, recover_missing_comment_in_span, rewrite_missing_comment,
16};
17use crate::config::lists::*;
18use crate::config::{BraceStyle, Config, IndentStyle, StyleEdition};
19use crate::expr::{
20    RhsAssignKind, RhsTactics, is_empty_block, is_simple_block_stmt, rewrite_assign_rhs,
21    rewrite_assign_rhs_with, rewrite_assign_rhs_with_comments, rewrite_else_kw_with_comments,
22    rewrite_let_else_block,
23};
24use crate::lists::{ListFormatting, Separator, definitive_tactic, itemize_list, write_list};
25use crate::macros::{MacroPosition, rewrite_macro};
26use crate::overflow;
27use crate::rewrite::{Rewrite, RewriteContext, RewriteError, RewriteErrorExt, RewriteResult};
28use crate::shape::{Indent, Shape};
29use crate::source_map::{LineRangeUtils, SpanUtils};
30use crate::spanned::Spanned;
31use crate::stmt::Stmt;
32use crate::types::opaque_ty;
33use crate::utils::*;
34use crate::vertical::rewrite_with_alignment;
35use crate::visitor::FmtVisitor;
36
37const DEFAULT_VISIBILITY: ast::Visibility = ast::Visibility {
38    kind: ast::VisibilityKind::Inherited,
39    span: DUMMY_SP,
40    tokens: None,
41};
42
43fn type_annotation_separator(config: &Config) -> &str {
44    colon_spaces(config)
45}
46
47// Statements of the form
48// let pat: ty = init; or let pat: ty = init else { .. };
49impl Rewrite for ast::Local {
50    fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
51        self.rewrite_result(context, shape).ok()
52    }
53
54    fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult {
55        debug!(
56            "Local::rewrite {:?} {} {:?}",
57            self, shape.width, shape.indent
58        );
59
60        skip_out_of_file_lines_range_err!(context, self.span);
61
62        if contains_skip(&self.attrs) {
63            return Err(RewriteError::SkipFormatting);
64        }
65
66        // FIXME(super_let): Implement formatting
67        if self.super_.is_some() {
68            return Err(RewriteError::SkipFormatting);
69        }
70
71        let attrs_str = self.attrs.rewrite_result(context, shape)?;
72        let mut result = if attrs_str.is_empty() {
73            "let ".to_owned()
74        } else {
75            combine_strs_with_missing_comments(
76                context,
77                &attrs_str,
78                "let ",
79                mk_sp(
80                    self.attrs.last().map(|a| a.span.hi()).unwrap(),
81                    self.span.lo(),
82                ),
83                shape,
84                false,
85            )?
86        };
87        let let_kw_offset = result.len() - "let ".len();
88
89        // 4 = "let ".len()
90        let pat_shape = shape
91            .offset_left(4)
92            .max_width_error(shape.width, self.span())?;
93        // 1 = ;
94        let pat_shape = pat_shape
95            .sub_width(1)
96            .max_width_error(shape.width, self.span())?;
97        let pat_str = self.pat.rewrite_result(context, pat_shape)?;
98
99        result.push_str(&pat_str);
100
101        // String that is placed within the assignment pattern and expression.
102        let infix = {
103            let mut infix = String::with_capacity(32);
104
105            if let Some(ref ty) = self.ty {
106                let separator = type_annotation_separator(context.config);
107                let ty_shape = if pat_str.contains('\n') {
108                    shape.with_max_width(context.config)
109                } else {
110                    shape
111                }
112                .offset_left(last_line_width(&result) + separator.len())
113                .max_width_error(shape.width, self.span())?
114                // 2 = ` =`
115                .sub_width(2)
116                .max_width_error(shape.width, self.span())?;
117
118                let rewrite = ty.rewrite_result(context, ty_shape)?;
119
120                infix.push_str(separator);
121                infix.push_str(&rewrite);
122            }
123
124            if self.kind.init().is_some() {
125                infix.push_str(" =");
126            }
127
128            infix
129        };
130
131        result.push_str(&infix);
132
133        if let Some((init, else_block)) = self.kind.init_else_opt() {
134            // 1 = trailing semicolon;
135            let nested_shape = shape
136                .sub_width(1)
137                .max_width_error(shape.width, self.span())?;
138
139            result = rewrite_assign_rhs(
140                context,
141                result,
142                init,
143                &RhsAssignKind::Expr(&init.kind, init.span),
144                nested_shape,
145            )?;
146
147            if let Some(block) = else_block {
148                let else_kw_span = init.span.between(block.span);
149                // Strip attributes and comments to check if newline is needed before the else
150                // keyword from the initializer part. (#5901)
151                let style_edition = context.config.style_edition();
152                let init_str = if style_edition >= StyleEdition::Edition2024 {
153                    &result[let_kw_offset..]
154                } else {
155                    result.as_str()
156                };
157                let force_newline_else = pat_str.contains('\n')
158                    || !same_line_else_kw_and_brace(init_str, context, else_kw_span, nested_shape);
159                let else_kw = rewrite_else_kw_with_comments(
160                    force_newline_else,
161                    true,
162                    context,
163                    else_kw_span,
164                    shape,
165                );
166                result.push_str(&else_kw);
167
168                // At this point we've written `let {pat} = {expr} else' into the buffer, and we
169                // want to calculate up front if there's room to write the divergent block on the
170                // same line. The available space varies based on indentation so we clamp the width
171                // on the smaller of `shape.width` and `single_line_let_else_max_width`.
172                let max_width =
173                    std::cmp::min(shape.width, context.config.single_line_let_else_max_width());
174
175                // If available_space hits zero we know for sure this will be a multi-lined block
176                let style_edition = context.config.style_edition();
177                let assign_str_with_else_kw = if style_edition >= StyleEdition::Edition2024 {
178                    &result[let_kw_offset..]
179                } else {
180                    result.as_str()
181                };
182                let available_space = max_width.saturating_sub(assign_str_with_else_kw.len());
183
184                let allow_single_line = !force_newline_else
185                    && available_space > 0
186                    && allow_single_line_let_else_block(assign_str_with_else_kw, block);
187
188                let mut rw_else_block =
189                    rewrite_let_else_block(block, allow_single_line, context, shape)?;
190
191                let single_line_else = !rw_else_block.contains('\n');
192                // +1 for the trailing `;`
193                let else_block_exceeds_width = rw_else_block.len() + 1 > available_space;
194
195                if allow_single_line && single_line_else && else_block_exceeds_width {
196                    // writing this on one line would exceed the available width
197                    // so rewrite the else block over multiple lines.
198                    rw_else_block = rewrite_let_else_block(block, false, context, shape)?;
199                }
200
201                result.push_str(&rw_else_block);
202            };
203        }
204
205        result.push(';');
206        Ok(result)
207    }
208}
209
210/// When the initializer expression is multi-lined, then the else keyword and opening brace of the
211/// block ( i.e. "else {") should be put on the same line as the end of the initializer expression
212/// if all the following are true:
213///
214/// 1. The initializer expression ends with one or more closing parentheses, square brackets,
215///    or braces
216/// 2. There is nothing else on that line
217/// 3. That line is not indented beyond the indent on the first line of the let keyword
218fn same_line_else_kw_and_brace(
219    init_str: &str,
220    context: &RewriteContext<'_>,
221    else_kw_span: Span,
222    init_shape: Shape,
223) -> bool {
224    if !init_str.contains('\n') {
225        // initializer expression is single lined. The "else {" can only be placed on the same line
226        // as the initializer expression if there is enough room for it.
227        // 7 = ` else {`
228        return init_shape.width.saturating_sub(init_str.len()) >= 7;
229    }
230
231    // 1. The initializer expression ends with one or more `)`, `]`, `}`.
232    if !init_str.ends_with([')', ']', '}']) {
233        return false;
234    }
235
236    // 2. There is nothing else on that line
237    // For example, there are no comments
238    let else_kw_snippet = context.snippet(else_kw_span).trim();
239    if else_kw_snippet != "else" {
240        return false;
241    }
242
243    // 3. The last line of the initializer expression is not indented beyond the `let` keyword
244    let indent = init_shape.indent.to_string(context.config);
245    init_str
246        .lines()
247        .last()
248        .expect("initializer expression is multi-lined")
249        .strip_prefix(indent.as_ref())
250        .map_or(false, |l| !l.starts_with(char::is_whitespace))
251}
252
253fn allow_single_line_let_else_block(result: &str, block: &ast::Block) -> bool {
254    if result.contains('\n') {
255        return false;
256    }
257
258    if block.stmts.len() <= 1 {
259        return true;
260    }
261
262    false
263}
264
265// FIXME convert to using rewrite style rather than visitor
266// FIXME format modules in this style
267#[allow(dead_code)]
268#[derive(Debug)]
269struct Item<'a> {
270    safety: ast::Safety,
271    abi: Cow<'static, str>,
272    vis: Option<&'a ast::Visibility>,
273    body: Vec<BodyElement<'a>>,
274    span: Span,
275}
276
277impl<'a> Item<'a> {
278    fn from_foreign_mod(fm: &'a ast::ForeignMod, span: Span, config: &Config) -> Item<'a> {
279        Item {
280            safety: fm.safety,
281            abi: format_extern(
282                ast::Extern::from_abi(fm.abi, DUMMY_SP),
283                config.force_explicit_abi(),
284            ),
285            vis: None,
286            body: fm
287                .items
288                .iter()
289                .map(|i| BodyElement::ForeignItem(i))
290                .collect(),
291            span,
292        }
293    }
294}
295
296#[derive(Debug)]
297enum BodyElement<'a> {
298    // Stmt(&'a ast::Stmt),
299    // Field(&'a ast::ExprField),
300    // Variant(&'a ast::Variant),
301    // Item(&'a ast::Item),
302    ForeignItem(&'a ast::ForeignItem),
303}
304
305/// Represents a fn's signature.
306pub(crate) struct FnSig<'a> {
307    decl: &'a ast::FnDecl,
308    generics: &'a ast::Generics,
309    ext: ast::Extern,
310    coroutine_kind: Cow<'a, Option<ast::CoroutineKind>>,
311    constness: ast::Const,
312    defaultness: ast::Defaultness,
313    safety: ast::Safety,
314    visibility: &'a ast::Visibility,
315}
316
317impl<'a> FnSig<'a> {
318    pub(crate) fn from_method_sig(
319        method_sig: &'a ast::FnSig,
320        generics: &'a ast::Generics,
321        visibility: &'a ast::Visibility,
322    ) -> FnSig<'a> {
323        FnSig {
324            safety: method_sig.header.safety,
325            coroutine_kind: Cow::Borrowed(&method_sig.header.coroutine_kind),
326            constness: method_sig.header.constness,
327            defaultness: ast::Defaultness::Final,
328            ext: method_sig.header.ext,
329            decl: &*method_sig.decl,
330            generics,
331            visibility,
332        }
333    }
334
335    pub(crate) fn from_fn_kind(
336        fn_kind: &'a visit::FnKind<'_>,
337        decl: &'a ast::FnDecl,
338        defaultness: ast::Defaultness,
339    ) -> FnSig<'a> {
340        match *fn_kind {
341            visit::FnKind::Fn(visit::FnCtxt::Assoc(..), vis, ast::Fn { sig, generics, .. }) => {
342                let mut fn_sig = FnSig::from_method_sig(sig, generics, vis);
343                fn_sig.defaultness = defaultness;
344                fn_sig
345            }
346            visit::FnKind::Fn(_, vis, ast::Fn { sig, generics, .. }) => FnSig {
347                decl,
348                generics,
349                ext: sig.header.ext,
350                constness: sig.header.constness,
351                coroutine_kind: Cow::Borrowed(&sig.header.coroutine_kind),
352                defaultness,
353                safety: sig.header.safety,
354                visibility: vis,
355            },
356            _ => unreachable!(),
357        }
358    }
359
360    fn to_str(&self, context: &RewriteContext<'_>) -> String {
361        let mut result = String::with_capacity(128);
362        // Vis defaultness constness unsafety abi.
363        result.push_str(&*format_visibility(context, self.visibility));
364        result.push_str(format_defaultness(self.defaultness));
365        result.push_str(format_constness(self.constness));
366        self.coroutine_kind
367            .map(|coroutine_kind| result.push_str(format_coro(&coroutine_kind)));
368        result.push_str(format_safety(self.safety));
369        result.push_str(&format_extern(
370            self.ext,
371            context.config.force_explicit_abi(),
372        ));
373        result
374    }
375}
376
377impl<'a> FmtVisitor<'a> {
378    fn format_item(&mut self, item: &Item<'_>) {
379        self.buffer.push_str(format_safety(item.safety));
380        self.buffer.push_str(&item.abi);
381
382        let snippet = self.snippet(item.span);
383        let brace_pos = snippet.find_uncommented("{").unwrap();
384
385        self.push_str("{");
386        if !item.body.is_empty() || contains_comment(&snippet[brace_pos..]) {
387            // FIXME: this skips comments between the extern keyword and the opening
388            // brace.
389            self.last_pos = item.span.lo() + BytePos(brace_pos as u32 + 1);
390            self.block_indent = self.block_indent.block_indent(self.config);
391
392            if !item.body.is_empty() {
393                for item in &item.body {
394                    self.format_body_element(item);
395                }
396            }
397
398            self.format_missing_no_indent(item.span.hi() - BytePos(1));
399            self.block_indent = self.block_indent.block_unindent(self.config);
400            let indent_str = self.block_indent.to_string(self.config);
401            self.push_str(&indent_str);
402        }
403
404        self.push_str("}");
405        self.last_pos = item.span.hi();
406    }
407
408    fn format_body_element(&mut self, element: &BodyElement<'_>) {
409        match *element {
410            BodyElement::ForeignItem(item) => self.format_foreign_item(item),
411        }
412    }
413
414    pub(crate) fn format_foreign_mod(&mut self, fm: &ast::ForeignMod, span: Span) {
415        let item = Item::from_foreign_mod(fm, span, self.config);
416        self.format_item(&item);
417    }
418
419    fn format_foreign_item(&mut self, item: &ast::ForeignItem) {
420        let rewrite = item.rewrite(&self.get_context(), self.shape());
421        let hi = item.span.hi();
422        let span = if item.attrs.is_empty() {
423            item.span
424        } else {
425            mk_sp(item.attrs[0].span.lo(), hi)
426        };
427        self.push_rewrite(span, rewrite);
428        self.last_pos = hi;
429    }
430
431    pub(crate) fn rewrite_fn_before_block(
432        &mut self,
433        indent: Indent,
434        ident: symbol::Ident,
435        fn_sig: &FnSig<'_>,
436        span: Span,
437    ) -> Option<(String, FnBraceStyle)> {
438        let context = self.get_context();
439
440        let mut fn_brace_style = newline_for_brace(self.config, &fn_sig.generics.where_clause);
441        let (result, _, force_newline_brace) =
442            rewrite_fn_base(&context, indent, ident, fn_sig, span, fn_brace_style).ok()?;
443
444        // 2 = ` {`
445        if self.config.brace_style() == BraceStyle::AlwaysNextLine
446            || force_newline_brace
447            || last_line_width(&result) + 2 > self.shape().width
448        {
449            fn_brace_style = FnBraceStyle::NextLine
450        }
451
452        Some((result, fn_brace_style))
453    }
454
455    pub(crate) fn rewrite_required_fn(
456        &mut self,
457        indent: Indent,
458        ident: symbol::Ident,
459        sig: &ast::FnSig,
460        vis: &ast::Visibility,
461        generics: &ast::Generics,
462        span: Span,
463    ) -> RewriteResult {
464        // Drop semicolon or it will be interpreted as comment.
465        let span = mk_sp(span.lo(), span.hi() - BytePos(1));
466        let context = self.get_context();
467
468        let (mut result, ends_with_comment, _) = rewrite_fn_base(
469            &context,
470            indent,
471            ident,
472            &FnSig::from_method_sig(sig, generics, vis),
473            span,
474            FnBraceStyle::None,
475        )?;
476
477        // If `result` ends with a comment, then remember to add a newline
478        if ends_with_comment {
479            result.push_str(&indent.to_string_with_newline(context.config));
480        }
481
482        // Re-attach semicolon
483        result.push(';');
484
485        Ok(result)
486    }
487
488    pub(crate) fn single_line_fn(
489        &self,
490        fn_str: &str,
491        block: &ast::Block,
492        inner_attrs: Option<&[ast::Attribute]>,
493    ) -> Option<String> {
494        if fn_str.contains('\n') || inner_attrs.map_or(false, |a| !a.is_empty()) {
495            return None;
496        }
497
498        let context = self.get_context();
499
500        if self.config.empty_item_single_line()
501            && is_empty_block(&context, block, None)
502            && self.block_indent.width() + fn_str.len() + 3 <= self.config.max_width()
503            && !last_line_contains_single_line_comment(fn_str)
504        {
505            return Some(format!("{fn_str} {{}}"));
506        }
507
508        if !self.config.fn_single_line() || !is_simple_block_stmt(&context, block, None) {
509            return None;
510        }
511
512        let res = Stmt::from_ast_node(block.stmts.first()?, true)
513            .rewrite(&self.get_context(), self.shape())?;
514
515        let width = self.block_indent.width() + fn_str.len() + res.len() + 5;
516        if !res.contains('\n') && width <= self.config.max_width() {
517            Some(format!("{fn_str} {{ {res} }}"))
518        } else {
519            None
520        }
521    }
522
523    pub(crate) fn visit_static(&mut self, static_parts: &StaticParts<'_>) {
524        let rewrite = rewrite_static(&self.get_context(), static_parts, self.block_indent);
525        self.push_rewrite(static_parts.span, rewrite);
526    }
527
528    pub(crate) fn visit_struct(&mut self, struct_parts: &StructParts<'_>) {
529        let is_tuple = match struct_parts.def {
530            ast::VariantData::Tuple(..) => true,
531            _ => false,
532        };
533        let rewrite = format_struct(&self.get_context(), struct_parts, self.block_indent, None)
534            .map(|s| if is_tuple { s + ";" } else { s });
535        self.push_rewrite(struct_parts.span, rewrite);
536    }
537
538    pub(crate) fn visit_enum(
539        &mut self,
540        ident: symbol::Ident,
541        vis: &ast::Visibility,
542        enum_def: &ast::EnumDef,
543        generics: &ast::Generics,
544        span: Span,
545    ) {
546        let enum_header =
547            format_header(&self.get_context(), "enum ", ident, vis, self.block_indent);
548        self.push_str(&enum_header);
549
550        let enum_snippet = self.snippet(span);
551        let brace_pos = enum_snippet.find_uncommented("{").unwrap();
552        let body_start = span.lo() + BytePos(brace_pos as u32 + 1);
553        let generics_str = format_generics(
554            &self.get_context(),
555            generics,
556            self.config.brace_style(),
557            if enum_def.variants.is_empty() {
558                BracePos::ForceSameLine
559            } else {
560                BracePos::Auto
561            },
562            self.block_indent,
563            // make a span that starts right after `enum Foo`
564            mk_sp(ident.span.hi(), body_start),
565            last_line_width(&enum_header),
566        )
567        .unwrap();
568        self.push_str(&generics_str);
569
570        self.last_pos = body_start;
571
572        match self.format_variant_list(enum_def, body_start, span.hi()) {
573            Some(ref s) if enum_def.variants.is_empty() => self.push_str(s),
574            rw => {
575                self.push_rewrite(mk_sp(body_start, span.hi()), rw);
576                self.block_indent = self.block_indent.block_unindent(self.config);
577            }
578        }
579    }
580
581    // Format the body of an enum definition
582    fn format_variant_list(
583        &mut self,
584        enum_def: &ast::EnumDef,
585        body_lo: BytePos,
586        body_hi: BytePos,
587    ) -> Option<String> {
588        if enum_def.variants.is_empty() {
589            let mut buffer = String::with_capacity(128);
590            // 1 = "}"
591            let span = mk_sp(body_lo, body_hi - BytePos(1));
592            format_empty_struct_or_tuple(
593                &self.get_context(),
594                span,
595                self.block_indent,
596                &mut buffer,
597                "",
598                "}",
599            );
600            return Some(buffer);
601        }
602        let mut result = String::with_capacity(1024);
603        let original_offset = self.block_indent;
604        self.block_indent = self.block_indent.block_indent(self.config);
605
606        // If enum variants have discriminants, try to vertically align those,
607        // provided the discrims are not shifted too much  to the right
608        let align_threshold: usize = self.config.enum_discrim_align_threshold();
609        let discr_ident_lens: Vec<usize> = enum_def
610            .variants
611            .iter()
612            .filter(|var| var.disr_expr.is_some())
613            .map(|var| rewrite_ident(&self.get_context(), var.ident).len())
614            .collect();
615        // cut the list at the point of longest discrim shorter than the threshold
616        // All of the discrims under the threshold will get padded, and all above - left as is.
617        let pad_discrim_ident_to = *discr_ident_lens
618            .iter()
619            .filter(|&l| *l <= align_threshold)
620            .max()
621            .unwrap_or(&0);
622
623        let itemize_list_with = |one_line_width: usize| {
624            itemize_list(
625                self.snippet_provider,
626                enum_def.variants.iter(),
627                "}",
628                ",",
629                |f| {
630                    if !f.attrs.is_empty() {
631                        f.attrs[0].span.lo()
632                    } else {
633                        f.span.lo()
634                    }
635                },
636                |f| f.span.hi(),
637                |f| {
638                    self.format_variant(f, one_line_width, pad_discrim_ident_to)
639                        .unknown_error()
640                },
641                body_lo,
642                body_hi,
643                false,
644            )
645            .collect()
646        };
647        let mut items: Vec<_> = itemize_list_with(self.config.struct_variant_width());
648
649        // If one of the variants use multiple lines, use multi-lined formatting for all variants.
650        let has_multiline_variant = items.iter().any(|item| item.inner_as_ref().contains('\n'));
651        let has_single_line_variant = items.iter().any(|item| !item.inner_as_ref().contains('\n'));
652        if has_multiline_variant && has_single_line_variant {
653            items = itemize_list_with(0);
654        }
655
656        let shape = self.shape().sub_width(2)?;
657        let fmt = ListFormatting::new(shape, self.config)
658            .trailing_separator(self.config.trailing_comma())
659            .preserve_newline(true);
660
661        let list = write_list(&items, &fmt).ok()?;
662        result.push_str(&list);
663        result.push_str(&original_offset.to_string_with_newline(self.config));
664        result.push('}');
665        Some(result)
666    }
667
668    // Variant of an enum.
669    fn format_variant(
670        &self,
671        field: &ast::Variant,
672        one_line_width: usize,
673        pad_discrim_ident_to: usize,
674    ) -> Option<String> {
675        if contains_skip(&field.attrs) {
676            let lo = field.attrs[0].span.lo();
677            let span = mk_sp(lo, field.span.hi());
678            return Some(self.snippet(span).to_owned());
679        }
680
681        let context = self.get_context();
682        let shape = self.shape();
683        let attrs_str = if context.config.style_edition() >= StyleEdition::Edition2024 {
684            field.attrs.rewrite(&context, shape)?
685        } else {
686            // StyleEdition::Edition20{15|18|21} formatting that was off by 1. See issue #5801
687            field.attrs.rewrite(&context, shape.sub_width(1)?)?
688        };
689        // sub_width(1) to take the trailing comma into account
690        let shape = shape.sub_width(1)?;
691
692        let lo = field
693            .attrs
694            .last()
695            .map_or(field.span.lo(), |attr| attr.span.hi());
696        let span = mk_sp(lo, field.span.lo());
697
698        let variant_body = match field.data {
699            ast::VariantData::Tuple(..) | ast::VariantData::Struct { .. } => format_struct(
700                &context,
701                &StructParts::from_variant(field, &context),
702                self.block_indent,
703                Some(one_line_width),
704            )?,
705            ast::VariantData::Unit(..) => rewrite_ident(&context, field.ident).to_owned(),
706        };
707
708        let variant_body = if let Some(ref expr) = field.disr_expr {
709            let lhs = format!("{variant_body:pad_discrim_ident_to$} =");
710            let ex = &*expr.value;
711            rewrite_assign_rhs_with(
712                &context,
713                lhs,
714                ex,
715                shape,
716                &RhsAssignKind::Expr(&ex.kind, ex.span),
717                RhsTactics::AllowOverflow,
718            )
719            .ok()?
720        } else {
721            variant_body
722        };
723
724        combine_strs_with_missing_comments(&context, &attrs_str, &variant_body, span, shape, false)
725            .ok()
726    }
727
728    fn visit_impl_items(&mut self, items: &[ptr::P<ast::AssocItem>]) {
729        if self.get_context().config.reorder_impl_items() {
730            type TyOpt = Option<ptr::P<ast::Ty>>;
731            use crate::ast::AssocItemKind::*;
732            let is_type = |ty: &TyOpt| opaque_ty(ty).is_none();
733            let is_opaque = |ty: &TyOpt| opaque_ty(ty).is_some();
734            let both_type = |l: &TyOpt, r: &TyOpt| is_type(l) && is_type(r);
735            let both_opaque = |l: &TyOpt, r: &TyOpt| is_opaque(l) && is_opaque(r);
736            let need_empty_line = |a: &ast::AssocItemKind, b: &ast::AssocItemKind| match (a, b) {
737                (Type(lty), Type(rty))
738                    if both_type(&lty.ty, &rty.ty) || both_opaque(&lty.ty, &rty.ty) =>
739                {
740                    false
741                }
742                (Const(..), Const(..)) => false,
743                _ => true,
744            };
745
746            // Create visitor for each items, then reorder them.
747            let mut buffer = vec![];
748            for item in items {
749                self.visit_impl_item(item);
750                buffer.push((self.buffer.clone(), item.clone()));
751                self.buffer.clear();
752            }
753
754            buffer.sort_by(|(_, a), (_, b)| match (&a.kind, &b.kind) {
755                (Type(lty), Type(rty))
756                    if both_type(&lty.ty, &rty.ty) || both_opaque(&lty.ty, &rty.ty) =>
757                {
758                    lty.ident.as_str().cmp(rty.ident.as_str())
759                }
760                (Const(ca), Const(cb)) => ca.ident.as_str().cmp(cb.ident.as_str()),
761                (MacCall(..), MacCall(..)) => Ordering::Equal,
762                (Fn(..), Fn(..)) | (Delegation(..), Delegation(..)) => {
763                    a.span.lo().cmp(&b.span.lo())
764                }
765                (Type(ty), _) if is_type(&ty.ty) => Ordering::Less,
766                (_, Type(ty)) if is_type(&ty.ty) => Ordering::Greater,
767                (Type(..), _) => Ordering::Less,
768                (_, Type(..)) => Ordering::Greater,
769                (Const(..), _) => Ordering::Less,
770                (_, Const(..)) => Ordering::Greater,
771                (MacCall(..), _) => Ordering::Less,
772                (_, MacCall(..)) => Ordering::Greater,
773                (Delegation(..), _) | (DelegationMac(..), _) => Ordering::Less,
774                (_, Delegation(..)) | (_, DelegationMac(..)) => Ordering::Greater,
775            });
776            let mut prev_kind = None;
777            for (buf, item) in buffer {
778                // Make sure that there are at least a single empty line between
779                // different impl items.
780                if prev_kind
781                    .as_ref()
782                    .map_or(false, |prev_kind| need_empty_line(prev_kind, &item.kind))
783                {
784                    self.push_str("\n");
785                }
786                let indent_str = self.block_indent.to_string_with_newline(self.config);
787                self.push_str(&indent_str);
788                self.push_str(buf.trim());
789                prev_kind = Some(item.kind.clone());
790            }
791        } else {
792            for item in items {
793                self.visit_impl_item(item);
794            }
795        }
796    }
797}
798
799pub(crate) fn format_impl(
800    context: &RewriteContext<'_>,
801    item: &ast::Item,
802    iimpl: &ast::Impl,
803    offset: Indent,
804) -> Option<String> {
805    let ast::Impl {
806        generics,
807        self_ty,
808        items,
809        ..
810    } = iimpl;
811    let mut result = String::with_capacity(128);
812    let ref_and_type = format_impl_ref_and_type(context, item, iimpl, offset)?;
813    let sep = offset.to_string_with_newline(context.config);
814    result.push_str(&ref_and_type);
815
816    let where_budget = if result.contains('\n') {
817        context.config.max_width()
818    } else {
819        context.budget(last_line_width(&result))
820    };
821
822    let mut option = WhereClauseOption::snuggled(&ref_and_type);
823    let snippet = context.snippet(item.span);
824    let open_pos = snippet.find_uncommented("{")? + 1;
825    if !contains_comment(&snippet[open_pos..])
826        && items.is_empty()
827        && generics.where_clause.predicates.len() == 1
828        && !result.contains('\n')
829    {
830        option.suppress_comma();
831        option.snuggle();
832        option.allow_single_line();
833    }
834
835    let missing_span = mk_sp(self_ty.span.hi(), item.span.hi());
836    let where_span_end = context.snippet_provider.opt_span_before(missing_span, "{");
837    let where_clause_str = rewrite_where_clause(
838        context,
839        &generics.where_clause.predicates,
840        generics.where_clause.span,
841        context.config.brace_style(),
842        Shape::legacy(where_budget, offset.block_only()),
843        false,
844        "{",
845        where_span_end,
846        self_ty.span.hi(),
847        option,
848    )
849    .ok()?;
850
851    // If there is no where-clause, we may have missing comments between the trait name and
852    // the opening brace.
853    if generics.where_clause.predicates.is_empty() {
854        if let Some(hi) = where_span_end {
855            match recover_missing_comment_in_span(
856                mk_sp(self_ty.span.hi(), hi),
857                Shape::indented(offset, context.config),
858                context,
859                last_line_width(&result),
860            ) {
861                Ok(ref missing_comment) if !missing_comment.is_empty() => {
862                    result.push_str(missing_comment);
863                }
864                _ => (),
865            }
866        }
867    }
868
869    if is_impl_single_line(context, items.as_slice(), &result, &where_clause_str, item)? {
870        result.push_str(&where_clause_str);
871        if where_clause_str.contains('\n') {
872            // If there is only one where-clause predicate
873            // and the where-clause spans multiple lines,
874            // then recover the suppressed comma in single line where-clause formatting
875            if generics.where_clause.predicates.len() == 1 {
876                result.push(',');
877            }
878        }
879        if where_clause_str.contains('\n') || last_line_contains_single_line_comment(&result) {
880            result.push_str(&format!("{sep}{{{sep}}}"));
881        } else {
882            result.push_str(" {}");
883        }
884        return Some(result);
885    }
886
887    result.push_str(&where_clause_str);
888
889    let need_newline = last_line_contains_single_line_comment(&result) || result.contains('\n');
890    match context.config.brace_style() {
891        _ if need_newline => result.push_str(&sep),
892        BraceStyle::AlwaysNextLine => result.push_str(&sep),
893        BraceStyle::PreferSameLine => result.push(' '),
894        BraceStyle::SameLineWhere => {
895            if !where_clause_str.is_empty() {
896                result.push_str(&sep);
897            } else {
898                result.push(' ');
899            }
900        }
901    }
902
903    result.push('{');
904    // this is an impl body snippet(impl SampleImpl { /* here */ })
905    let lo = max(self_ty.span.hi(), generics.where_clause.span.hi());
906    let snippet = context.snippet(mk_sp(lo, item.span.hi()));
907    let open_pos = snippet.find_uncommented("{")? + 1;
908
909    if !items.is_empty() || contains_comment(&snippet[open_pos..]) {
910        let mut visitor = FmtVisitor::from_context(context);
911        let item_indent = offset.block_only().block_indent(context.config);
912        visitor.block_indent = item_indent;
913        visitor.last_pos = lo + BytePos(open_pos as u32);
914
915        visitor.visit_attrs(&item.attrs, ast::AttrStyle::Inner);
916        visitor.visit_impl_items(items);
917
918        visitor.format_missing(item.span.hi() - BytePos(1));
919
920        let inner_indent_str = visitor.block_indent.to_string_with_newline(context.config);
921        let outer_indent_str = offset.block_only().to_string_with_newline(context.config);
922
923        result.push_str(&inner_indent_str);
924        result.push_str(visitor.buffer.trim());
925        result.push_str(&outer_indent_str);
926    } else if need_newline || !context.config.empty_item_single_line() {
927        result.push_str(&sep);
928    }
929
930    result.push('}');
931
932    Some(result)
933}
934
935fn is_impl_single_line(
936    context: &RewriteContext<'_>,
937    items: &[ptr::P<ast::AssocItem>],
938    result: &str,
939    where_clause_str: &str,
940    item: &ast::Item,
941) -> Option<bool> {
942    let snippet = context.snippet(item.span);
943    let open_pos = snippet.find_uncommented("{")? + 1;
944
945    Some(
946        context.config.empty_item_single_line()
947            && items.is_empty()
948            && !result.contains('\n')
949            && result.len() + where_clause_str.len() <= context.config.max_width()
950            && !contains_comment(&snippet[open_pos..]),
951    )
952}
953
954fn format_impl_ref_and_type(
955    context: &RewriteContext<'_>,
956    item: &ast::Item,
957    iimpl: &ast::Impl,
958    offset: Indent,
959) -> Option<String> {
960    let ast::Impl {
961        safety,
962        polarity,
963        defaultness,
964        constness,
965        ref generics,
966        of_trait: ref trait_ref,
967        ref self_ty,
968        ..
969    } = *iimpl;
970    let mut result = String::with_capacity(128);
971
972    result.push_str(&format_visibility(context, &item.vis));
973    result.push_str(format_defaultness(defaultness));
974    result.push_str(format_safety(safety));
975
976    let shape = if context.config.style_edition() >= StyleEdition::Edition2024 {
977        Shape::indented(offset + last_line_width(&result), context.config)
978    } else {
979        generics_shape_from_config(
980            context.config,
981            Shape::indented(offset + last_line_width(&result), context.config),
982            0,
983        )?
984    };
985    let generics_str = rewrite_generics(context, "impl", generics, shape).ok()?;
986    result.push_str(&generics_str);
987    result.push_str(format_constness_right(constness));
988
989    let polarity_str = match polarity {
990        ast::ImplPolarity::Negative(_) => "!",
991        ast::ImplPolarity::Positive => "",
992    };
993
994    let polarity_overhead;
995    let trait_ref_overhead;
996    if let Some(ref trait_ref) = *trait_ref {
997        let result_len = last_line_width(&result);
998        result.push_str(&rewrite_trait_ref(
999            context,
1000            trait_ref,
1001            offset,
1002            polarity_str,
1003            result_len,
1004        )?);
1005        polarity_overhead = 0; // already written
1006        trait_ref_overhead = " for".len();
1007    } else {
1008        polarity_overhead = polarity_str.len();
1009        trait_ref_overhead = 0;
1010    }
1011
1012    // Try to put the self type in a single line.
1013    let curly_brace_overhead = if generics.where_clause.predicates.is_empty() {
1014        // If there is no where-clause adapt budget for type formatting to take space and curly
1015        // brace into account.
1016        match context.config.brace_style() {
1017            BraceStyle::AlwaysNextLine => 0,
1018            _ => 2,
1019        }
1020    } else {
1021        0
1022    };
1023    let used_space =
1024        last_line_width(&result) + polarity_overhead + trait_ref_overhead + curly_brace_overhead;
1025    // 1 = space before the type.
1026    let budget = context.budget(used_space + 1);
1027    if let Some(self_ty_str) = self_ty.rewrite(context, Shape::legacy(budget, offset)) {
1028        if !self_ty_str.contains('\n') {
1029            if trait_ref.is_some() {
1030                result.push_str(" for ");
1031            } else {
1032                result.push(' ');
1033                result.push_str(polarity_str);
1034            }
1035            result.push_str(&self_ty_str);
1036            return Some(result);
1037        }
1038    }
1039
1040    // Couldn't fit the self type on a single line, put it on a new line.
1041    result.push('\n');
1042    // Add indentation of one additional tab.
1043    let new_line_offset = offset.block_indent(context.config);
1044    result.push_str(&new_line_offset.to_string(context.config));
1045    if trait_ref.is_some() {
1046        result.push_str("for ");
1047    } else {
1048        result.push_str(polarity_str);
1049    }
1050    let budget = context.budget(last_line_width(&result) + polarity_overhead);
1051    let type_offset = match context.config.indent_style() {
1052        IndentStyle::Visual => new_line_offset + trait_ref_overhead,
1053        IndentStyle::Block => new_line_offset,
1054    };
1055    result.push_str(&*self_ty.rewrite(context, Shape::legacy(budget, type_offset))?);
1056    Some(result)
1057}
1058
1059fn rewrite_trait_ref(
1060    context: &RewriteContext<'_>,
1061    trait_ref: &ast::TraitRef,
1062    offset: Indent,
1063    polarity_str: &str,
1064    result_len: usize,
1065) -> Option<String> {
1066    // 1 = space between generics and trait_ref
1067    let used_space = 1 + polarity_str.len() + result_len;
1068    let shape = Shape::indented(offset + used_space, context.config);
1069    if let Some(trait_ref_str) = trait_ref.rewrite(context, shape) {
1070        if !trait_ref_str.contains('\n') {
1071            return Some(format!(" {polarity_str}{trait_ref_str}"));
1072        }
1073    }
1074    // We could not make enough space for trait_ref, so put it on new line.
1075    let offset = offset.block_indent(context.config);
1076    let shape = Shape::indented(offset, context.config);
1077    let trait_ref_str = trait_ref.rewrite(context, shape)?;
1078    Some(format!(
1079        "{}{}{}",
1080        offset.to_string_with_newline(context.config),
1081        polarity_str,
1082        trait_ref_str
1083    ))
1084}
1085
1086pub(crate) struct StructParts<'a> {
1087    prefix: &'a str,
1088    ident: symbol::Ident,
1089    vis: &'a ast::Visibility,
1090    def: &'a ast::VariantData,
1091    generics: Option<&'a ast::Generics>,
1092    span: Span,
1093}
1094
1095impl<'a> StructParts<'a> {
1096    fn format_header(&self, context: &RewriteContext<'_>, offset: Indent) -> String {
1097        format_header(context, self.prefix, self.ident, self.vis, offset)
1098    }
1099
1100    fn from_variant(variant: &'a ast::Variant, context: &RewriteContext<'_>) -> Self {
1101        StructParts {
1102            prefix: "",
1103            ident: variant.ident,
1104            vis: &DEFAULT_VISIBILITY,
1105            def: &variant.data,
1106            generics: None,
1107            span: enum_variant_span(variant, context),
1108        }
1109    }
1110
1111    pub(crate) fn from_item(item: &'a ast::Item) -> Self {
1112        let (prefix, def, ident, generics) = match item.kind {
1113            ast::ItemKind::Struct(ident, ref generics, ref def) => {
1114                ("struct ", def, ident, generics)
1115            }
1116            ast::ItemKind::Union(ident, ref generics, ref def) => ("union ", def, ident, generics),
1117            _ => unreachable!(),
1118        };
1119        StructParts {
1120            prefix,
1121            ident,
1122            vis: &item.vis,
1123            def,
1124            generics: Some(generics),
1125            span: item.span,
1126        }
1127    }
1128}
1129
1130fn enum_variant_span(variant: &ast::Variant, context: &RewriteContext<'_>) -> Span {
1131    use ast::VariantData::*;
1132    if let Some(ref anon_const) = variant.disr_expr {
1133        let span_before_consts = variant.span.until(anon_const.value.span);
1134        let hi = match &variant.data {
1135            Struct { .. } => context
1136                .snippet_provider
1137                .span_after_last(span_before_consts, "}"),
1138            Tuple(..) => context
1139                .snippet_provider
1140                .span_after_last(span_before_consts, ")"),
1141            Unit(..) => variant.ident.span.hi(),
1142        };
1143        mk_sp(span_before_consts.lo(), hi)
1144    } else {
1145        variant.span
1146    }
1147}
1148
1149fn format_struct(
1150    context: &RewriteContext<'_>,
1151    struct_parts: &StructParts<'_>,
1152    offset: Indent,
1153    one_line_width: Option<usize>,
1154) -> Option<String> {
1155    match struct_parts.def {
1156        ast::VariantData::Unit(..) => format_unit_struct(context, struct_parts, offset),
1157        ast::VariantData::Tuple(fields, _) => {
1158            format_tuple_struct(context, struct_parts, fields, offset)
1159        }
1160        ast::VariantData::Struct { fields, .. } => {
1161            format_struct_struct(context, struct_parts, fields, offset, one_line_width)
1162        }
1163    }
1164}
1165
1166pub(crate) fn format_trait(
1167    context: &RewriteContext<'_>,
1168    item: &ast::Item,
1169    offset: Indent,
1170) -> Option<String> {
1171    let ast::ItemKind::Trait(trait_kind) = &item.kind else {
1172        unreachable!();
1173    };
1174    let ast::Trait {
1175        constness,
1176        is_auto,
1177        safety,
1178        ident,
1179        ref generics,
1180        ref bounds,
1181        ref items,
1182    } = **trait_kind;
1183
1184    let mut result = String::with_capacity(128);
1185    let header = format!(
1186        "{}{}{}{}trait ",
1187        format_constness(constness),
1188        format_visibility(context, &item.vis),
1189        format_safety(safety),
1190        format_auto(is_auto),
1191    );
1192    result.push_str(&header);
1193
1194    let body_lo = context.snippet_provider.span_after(item.span, "{");
1195
1196    let shape = Shape::indented(offset, context.config).offset_left(result.len())?;
1197    let generics_str =
1198        rewrite_generics(context, rewrite_ident(context, ident), generics, shape).ok()?;
1199    result.push_str(&generics_str);
1200
1201    // FIXME(#2055): rustfmt fails to format when there are comments between trait bounds.
1202    if !bounds.is_empty() {
1203        // Retrieve *unnormalized* ident (See #6069)
1204        let source_ident = context.snippet(ident.span);
1205        let ident_hi = context.snippet_provider.span_after(item.span, source_ident);
1206        let bound_hi = bounds.last().unwrap().span().hi();
1207        let snippet = context.snippet(mk_sp(ident_hi, bound_hi));
1208        if contains_comment(snippet) {
1209            return None;
1210        }
1211
1212        result = rewrite_assign_rhs_with(
1213            context,
1214            result + ":",
1215            bounds,
1216            shape,
1217            &RhsAssignKind::Bounds,
1218            RhsTactics::ForceNextLineWithoutIndent,
1219        )
1220        .ok()?;
1221    }
1222
1223    // Rewrite where-clause.
1224    if !generics.where_clause.predicates.is_empty() {
1225        let where_on_new_line = context.config.indent_style() != IndentStyle::Block;
1226
1227        let where_budget = context.budget(last_line_width(&result));
1228        let pos_before_where = if bounds.is_empty() {
1229            generics.where_clause.span.lo()
1230        } else {
1231            bounds[bounds.len() - 1].span().hi()
1232        };
1233        let option = WhereClauseOption::snuggled(&generics_str);
1234        let where_clause_str = rewrite_where_clause(
1235            context,
1236            &generics.where_clause.predicates,
1237            generics.where_clause.span,
1238            context.config.brace_style(),
1239            Shape::legacy(where_budget, offset.block_only()),
1240            where_on_new_line,
1241            "{",
1242            None,
1243            pos_before_where,
1244            option,
1245        )
1246        .ok()?;
1247        // If the where-clause cannot fit on the same line,
1248        // put the where-clause on a new line
1249        if !where_clause_str.contains('\n')
1250            && last_line_width(&result) + where_clause_str.len() + offset.width()
1251                > context.config.comment_width()
1252        {
1253            let width = offset.block_indent + context.config.tab_spaces() - 1;
1254            let where_indent = Indent::new(0, width);
1255            result.push_str(&where_indent.to_string_with_newline(context.config));
1256        }
1257        result.push_str(&where_clause_str);
1258    } else {
1259        let item_snippet = context.snippet(item.span);
1260        if let Some(lo) = item_snippet.find('/') {
1261            // 1 = `{`
1262            let comment_hi = if generics.params.len() > 0 {
1263                generics.span.lo() - BytePos(1)
1264            } else {
1265                body_lo - BytePos(1)
1266            };
1267            let comment_lo = item.span.lo() + BytePos(lo as u32);
1268            if comment_lo < comment_hi {
1269                match recover_missing_comment_in_span(
1270                    mk_sp(comment_lo, comment_hi),
1271                    Shape::indented(offset, context.config),
1272                    context,
1273                    last_line_width(&result),
1274                ) {
1275                    Ok(ref missing_comment) if !missing_comment.is_empty() => {
1276                        result.push_str(missing_comment);
1277                    }
1278                    _ => (),
1279                }
1280            }
1281        }
1282    }
1283
1284    let block_span = mk_sp(generics.where_clause.span.hi(), item.span.hi());
1285    let snippet = context.snippet(block_span);
1286    let open_pos = snippet.find_uncommented("{")? + 1;
1287
1288    match context.config.brace_style() {
1289        _ if last_line_contains_single_line_comment(&result)
1290            || last_line_width(&result) + 2 > context.budget(offset.width()) =>
1291        {
1292            result.push_str(&offset.to_string_with_newline(context.config));
1293        }
1294        _ if context.config.empty_item_single_line()
1295            && items.is_empty()
1296            && !result.contains('\n')
1297            && !contains_comment(&snippet[open_pos..]) =>
1298        {
1299            result.push_str(" {}");
1300            return Some(result);
1301        }
1302        BraceStyle::AlwaysNextLine => {
1303            result.push_str(&offset.to_string_with_newline(context.config));
1304        }
1305        BraceStyle::PreferSameLine => result.push(' '),
1306        BraceStyle::SameLineWhere => {
1307            if result.contains('\n')
1308                || (!generics.where_clause.predicates.is_empty() && !items.is_empty())
1309            {
1310                result.push_str(&offset.to_string_with_newline(context.config));
1311            } else {
1312                result.push(' ');
1313            }
1314        }
1315    }
1316    result.push('{');
1317
1318    let outer_indent_str = offset.block_only().to_string_with_newline(context.config);
1319
1320    if !items.is_empty() || contains_comment(&snippet[open_pos..]) {
1321        let mut visitor = FmtVisitor::from_context(context);
1322        visitor.block_indent = offset.block_only().block_indent(context.config);
1323        visitor.last_pos = block_span.lo() + BytePos(open_pos as u32);
1324
1325        for item in items {
1326            visitor.visit_trait_item(item);
1327        }
1328
1329        visitor.format_missing(item.span.hi() - BytePos(1));
1330
1331        let inner_indent_str = visitor.block_indent.to_string_with_newline(context.config);
1332
1333        result.push_str(&inner_indent_str);
1334        result.push_str(visitor.buffer.trim());
1335        result.push_str(&outer_indent_str);
1336    } else if result.contains('\n') {
1337        result.push_str(&outer_indent_str);
1338    }
1339
1340    result.push('}');
1341    Some(result)
1342}
1343
1344pub(crate) struct TraitAliasBounds<'a> {
1345    generic_bounds: &'a ast::GenericBounds,
1346    generics: &'a ast::Generics,
1347}
1348
1349impl<'a> Rewrite for TraitAliasBounds<'a> {
1350    fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
1351        self.rewrite_result(context, shape).ok()
1352    }
1353
1354    fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult {
1355        let generic_bounds_str = self.generic_bounds.rewrite_result(context, shape)?;
1356
1357        let mut option = WhereClauseOption::new(true, WhereClauseSpace::None);
1358        option.allow_single_line();
1359
1360        let where_str = rewrite_where_clause(
1361            context,
1362            &self.generics.where_clause.predicates,
1363            self.generics.where_clause.span,
1364            context.config.brace_style(),
1365            shape,
1366            false,
1367            ";",
1368            None,
1369            self.generics.where_clause.span.lo(),
1370            option,
1371        )?;
1372
1373        let fits_single_line = !generic_bounds_str.contains('\n')
1374            && !where_str.contains('\n')
1375            && generic_bounds_str.len() + where_str.len() < shape.width;
1376        let space = if generic_bounds_str.is_empty() || where_str.is_empty() {
1377            Cow::from("")
1378        } else if fits_single_line {
1379            Cow::from(" ")
1380        } else {
1381            shape.indent.to_string_with_newline(context.config)
1382        };
1383
1384        Ok(format!("{generic_bounds_str}{space}{where_str}"))
1385    }
1386}
1387
1388pub(crate) fn format_trait_alias(
1389    context: &RewriteContext<'_>,
1390    ident: symbol::Ident,
1391    vis: &ast::Visibility,
1392    generics: &ast::Generics,
1393    generic_bounds: &ast::GenericBounds,
1394    shape: Shape,
1395) -> Option<String> {
1396    let alias = rewrite_ident(context, ident);
1397    // 6 = "trait ", 2 = " ="
1398    let g_shape = shape.offset_left(6)?.sub_width(2)?;
1399    let generics_str = rewrite_generics(context, alias, generics, g_shape).ok()?;
1400    let vis_str = format_visibility(context, vis);
1401    let lhs = format!("{vis_str}trait {generics_str} =");
1402    // 1 = ";"
1403    let trait_alias_bounds = TraitAliasBounds {
1404        generic_bounds,
1405        generics,
1406    };
1407    rewrite_assign_rhs(
1408        context,
1409        lhs,
1410        &trait_alias_bounds,
1411        &RhsAssignKind::Bounds,
1412        shape.sub_width(1)?,
1413    )
1414    .map(|s| s + ";")
1415    .ok()
1416}
1417
1418fn format_unit_struct(
1419    context: &RewriteContext<'_>,
1420    p: &StructParts<'_>,
1421    offset: Indent,
1422) -> Option<String> {
1423    let header_str = format_header(context, p.prefix, p.ident, p.vis, offset);
1424    let generics_str = if let Some(generics) = p.generics {
1425        let hi = context.snippet_provider.span_before_last(p.span, ";");
1426        format_generics(
1427            context,
1428            generics,
1429            context.config.brace_style(),
1430            BracePos::None,
1431            offset,
1432            // make a span that starts right after `struct Foo`
1433            mk_sp(p.ident.span.hi(), hi),
1434            last_line_width(&header_str),
1435        )?
1436    } else {
1437        String::new()
1438    };
1439    Some(format!("{header_str}{generics_str};"))
1440}
1441
1442pub(crate) fn format_struct_struct(
1443    context: &RewriteContext<'_>,
1444    struct_parts: &StructParts<'_>,
1445    fields: &[ast::FieldDef],
1446    offset: Indent,
1447    one_line_width: Option<usize>,
1448) -> Option<String> {
1449    let mut result = String::with_capacity(1024);
1450    let span = struct_parts.span;
1451
1452    let header_str = struct_parts.format_header(context, offset);
1453    result.push_str(&header_str);
1454
1455    let header_hi = struct_parts.ident.span.hi();
1456    let body_lo = if let Some(generics) = struct_parts.generics {
1457        // Adjust the span to start at the end of the generic arguments before searching for the '{'
1458        let span = span.with_lo(generics.where_clause.span.hi());
1459        context.snippet_provider.span_after(span, "{")
1460    } else {
1461        context.snippet_provider.span_after(span, "{")
1462    };
1463
1464    let generics_str = match struct_parts.generics {
1465        Some(g) => format_generics(
1466            context,
1467            g,
1468            context.config.brace_style(),
1469            if fields.is_empty() {
1470                BracePos::ForceSameLine
1471            } else {
1472                BracePos::Auto
1473            },
1474            offset,
1475            // make a span that starts right after `struct Foo`
1476            mk_sp(header_hi, body_lo),
1477            last_line_width(&result),
1478        )?,
1479        None => {
1480            // 3 = ` {}`, 2 = ` {`.
1481            let overhead = if fields.is_empty() { 3 } else { 2 };
1482            if (context.config.brace_style() == BraceStyle::AlwaysNextLine && !fields.is_empty())
1483                || context.config.max_width() < overhead + result.len()
1484            {
1485                format!("\n{}{{", offset.block_only().to_string(context.config))
1486            } else {
1487                " {".to_owned()
1488            }
1489        }
1490    };
1491    // 1 = `}`
1492    let overhead = if fields.is_empty() { 1 } else { 0 };
1493    let total_width = result.len() + generics_str.len() + overhead;
1494    if !generics_str.is_empty()
1495        && !generics_str.contains('\n')
1496        && total_width > context.config.max_width()
1497    {
1498        result.push('\n');
1499        result.push_str(&offset.to_string(context.config));
1500        result.push_str(generics_str.trim_start());
1501    } else {
1502        result.push_str(&generics_str);
1503    }
1504
1505    if fields.is_empty() {
1506        let inner_span = mk_sp(body_lo, span.hi() - BytePos(1));
1507        format_empty_struct_or_tuple(context, inner_span, offset, &mut result, "", "}");
1508        return Some(result);
1509    }
1510
1511    // 3 = ` ` and ` }`
1512    let one_line_budget = context.budget(result.len() + 3 + offset.width());
1513    let one_line_budget =
1514        one_line_width.map_or(0, |one_line_width| min(one_line_width, one_line_budget));
1515
1516    let items_str = rewrite_with_alignment(
1517        fields,
1518        context,
1519        Shape::indented(offset.block_indent(context.config), context.config).sub_width(1)?,
1520        mk_sp(body_lo, span.hi()),
1521        one_line_budget,
1522    )?;
1523
1524    if !items_str.contains('\n')
1525        && !result.contains('\n')
1526        && items_str.len() <= one_line_budget
1527        && !last_line_contains_single_line_comment(&items_str)
1528    {
1529        Some(format!("{result} {items_str} }}"))
1530    } else {
1531        Some(format!(
1532            "{}\n{}{}\n{}}}",
1533            result,
1534            offset
1535                .block_indent(context.config)
1536                .to_string(context.config),
1537            items_str,
1538            offset.to_string(context.config)
1539        ))
1540    }
1541}
1542
1543fn get_bytepos_after_visibility(vis: &ast::Visibility, default_span: Span) -> BytePos {
1544    match vis.kind {
1545        ast::VisibilityKind::Restricted { .. } => vis.span.hi(),
1546        _ => default_span.lo(),
1547    }
1548}
1549
1550// Format tuple or struct without any fields. We need to make sure that the comments
1551// inside the delimiters are preserved.
1552fn format_empty_struct_or_tuple(
1553    context: &RewriteContext<'_>,
1554    span: Span,
1555    offset: Indent,
1556    result: &mut String,
1557    opener: &str,
1558    closer: &str,
1559) {
1560    // 3 = " {}" or "();"
1561    let used_width = last_line_used_width(result, offset.width()) + 3;
1562    if used_width > context.config.max_width() {
1563        result.push_str(&offset.to_string_with_newline(context.config))
1564    }
1565    result.push_str(opener);
1566
1567    // indented shape for proper indenting of multi-line comments
1568    let shape = Shape::indented(offset.block_indent(context.config), context.config);
1569    match rewrite_missing_comment(span, shape, context) {
1570        Ok(ref s) if s.is_empty() => (),
1571        Ok(ref s) => {
1572            let is_multi_line = !is_single_line(s);
1573            if is_multi_line || first_line_contains_single_line_comment(s) {
1574                let nested_indent_str = offset
1575                    .block_indent(context.config)
1576                    .to_string_with_newline(context.config);
1577                result.push_str(&nested_indent_str);
1578            }
1579            result.push_str(s);
1580            if is_multi_line || last_line_contains_single_line_comment(s) {
1581                result.push_str(&offset.to_string_with_newline(context.config));
1582            }
1583        }
1584        Err(_) => result.push_str(context.snippet(span)),
1585    }
1586    result.push_str(closer);
1587}
1588
1589fn format_tuple_struct(
1590    context: &RewriteContext<'_>,
1591    struct_parts: &StructParts<'_>,
1592    fields: &[ast::FieldDef],
1593    offset: Indent,
1594) -> Option<String> {
1595    let mut result = String::with_capacity(1024);
1596    let span = struct_parts.span;
1597
1598    let header_str = struct_parts.format_header(context, offset);
1599    result.push_str(&header_str);
1600
1601    let body_lo = if fields.is_empty() {
1602        let lo = get_bytepos_after_visibility(struct_parts.vis, span);
1603        context
1604            .snippet_provider
1605            .span_after(mk_sp(lo, span.hi()), "(")
1606    } else {
1607        fields[0].span.lo()
1608    };
1609    let body_hi = if fields.is_empty() {
1610        context
1611            .snippet_provider
1612            .span_after(mk_sp(body_lo, span.hi()), ")")
1613    } else {
1614        // This is a dirty hack to work around a missing `)` from the span of the last field.
1615        let last_arg_span = fields[fields.len() - 1].span;
1616        context
1617            .snippet_provider
1618            .opt_span_after(mk_sp(last_arg_span.hi(), span.hi()), ")")
1619            .unwrap_or_else(|| last_arg_span.hi())
1620    };
1621
1622    let where_clause_str = match struct_parts.generics {
1623        Some(generics) => {
1624            let budget = context.budget(last_line_width(&header_str));
1625            let shape = Shape::legacy(budget, offset);
1626            let generics_str = rewrite_generics(context, "", generics, shape).ok()?;
1627            result.push_str(&generics_str);
1628
1629            let where_budget = context.budget(last_line_width(&result));
1630            let option = WhereClauseOption::new(true, WhereClauseSpace::Newline);
1631            rewrite_where_clause(
1632                context,
1633                &generics.where_clause.predicates,
1634                generics.where_clause.span,
1635                context.config.brace_style(),
1636                Shape::legacy(where_budget, offset.block_only()),
1637                false,
1638                ";",
1639                None,
1640                body_hi,
1641                option,
1642            )
1643            .ok()?
1644        }
1645        None => "".to_owned(),
1646    };
1647
1648    if fields.is_empty() {
1649        let body_hi = context
1650            .snippet_provider
1651            .span_before(mk_sp(body_lo, span.hi()), ")");
1652        let inner_span = mk_sp(body_lo, body_hi);
1653        format_empty_struct_or_tuple(context, inner_span, offset, &mut result, "(", ")");
1654    } else {
1655        let shape = Shape::indented(offset, context.config).sub_width(1)?;
1656        let lo = if let Some(generics) = struct_parts.generics {
1657            generics.span.hi()
1658        } else {
1659            struct_parts.ident.span.hi()
1660        };
1661        result = overflow::rewrite_with_parens(
1662            context,
1663            &result,
1664            fields.iter(),
1665            shape,
1666            mk_sp(lo, span.hi()),
1667            context.config.fn_call_width(),
1668            None,
1669        )
1670        .ok()?;
1671    }
1672
1673    if !where_clause_str.is_empty()
1674        && !where_clause_str.contains('\n')
1675        && (result.contains('\n')
1676            || offset.block_indent + result.len() + where_clause_str.len() + 1
1677                > context.config.max_width())
1678    {
1679        // We need to put the where-clause on a new line, but we didn't
1680        // know that earlier, so the where-clause will not be indented properly.
1681        result.push('\n');
1682        result.push_str(
1683            &(offset.block_only() + (context.config.tab_spaces() - 1)).to_string(context.config),
1684        );
1685    }
1686    result.push_str(&where_clause_str);
1687
1688    Some(result)
1689}
1690
1691#[derive(Clone, Copy)]
1692pub(crate) enum ItemVisitorKind {
1693    Item,
1694    AssocTraitItem,
1695    AssocImplItem,
1696    ForeignItem,
1697}
1698
1699struct TyAliasRewriteInfo<'c, 'g>(
1700    &'c RewriteContext<'c>,
1701    Indent,
1702    &'g ast::Generics,
1703    ast::TyAliasWhereClauses,
1704    symbol::Ident,
1705    Span,
1706);
1707
1708pub(crate) fn rewrite_type_alias<'a>(
1709    ty_alias_kind: &ast::TyAlias,
1710    vis: &ast::Visibility,
1711    context: &RewriteContext<'a>,
1712    indent: Indent,
1713    visitor_kind: ItemVisitorKind,
1714    span: Span,
1715) -> RewriteResult {
1716    use ItemVisitorKind::*;
1717
1718    let ast::TyAlias {
1719        defaultness,
1720        ident,
1721        ref generics,
1722        ref bounds,
1723        ref ty,
1724        where_clauses,
1725    } = *ty_alias_kind;
1726    let ty_opt = ty.as_ref();
1727    let rhs_hi = ty
1728        .as_ref()
1729        .map_or(where_clauses.before.span.hi(), |ty| ty.span.hi());
1730    let rw_info = &TyAliasRewriteInfo(context, indent, generics, where_clauses, ident, span);
1731    let op_ty = opaque_ty(ty);
1732    // Type Aliases are formatted slightly differently depending on the context
1733    // in which they appear, whether they are opaque, and whether they are associated.
1734    // https://rustc-dev-guide.rust-lang.org/opaque-types-type-alias-impl-trait.html
1735    // https://github.com/rust-dev-tools/fmt-rfcs/blob/master/guide/items.md#type-aliases
1736    match (visitor_kind, &op_ty) {
1737        (Item | AssocTraitItem | ForeignItem, Some(op_bounds)) => {
1738            let op = OpaqueType { bounds: op_bounds };
1739            rewrite_ty(rw_info, Some(bounds), Some(&op), rhs_hi, vis)
1740        }
1741        (Item | AssocTraitItem | ForeignItem, None) => {
1742            rewrite_ty(rw_info, Some(bounds), ty_opt, rhs_hi, vis)
1743        }
1744        (AssocImplItem, _) => {
1745            let result = if let Some(op_bounds) = op_ty {
1746                let op = OpaqueType { bounds: op_bounds };
1747                rewrite_ty(
1748                    rw_info,
1749                    Some(bounds),
1750                    Some(&op),
1751                    rhs_hi,
1752                    &DEFAULT_VISIBILITY,
1753                )
1754            } else {
1755                rewrite_ty(rw_info, Some(bounds), ty_opt, rhs_hi, vis)
1756            }?;
1757            match defaultness {
1758                ast::Defaultness::Default(..) => Ok(format!("default {result}")),
1759                _ => Ok(result),
1760            }
1761        }
1762    }
1763}
1764
1765fn rewrite_ty<R: Rewrite>(
1766    rw_info: &TyAliasRewriteInfo<'_, '_>,
1767    generic_bounds_opt: Option<&ast::GenericBounds>,
1768    rhs: Option<&R>,
1769    // the span of the end of the RHS (or the end of the generics, if there is no RHS)
1770    rhs_hi: BytePos,
1771    vis: &ast::Visibility,
1772) -> RewriteResult {
1773    let mut result = String::with_capacity(128);
1774    let TyAliasRewriteInfo(context, indent, generics, where_clauses, ident, span) = *rw_info;
1775    let (before_where_predicates, after_where_predicates) = generics
1776        .where_clause
1777        .predicates
1778        .split_at(where_clauses.split);
1779    result.push_str(&format!("{}type ", format_visibility(context, vis)));
1780    let ident_str = rewrite_ident(context, ident);
1781
1782    if generics.params.is_empty() {
1783        result.push_str(ident_str)
1784    } else {
1785        // 2 = `= `
1786        let g_shape = Shape::indented(indent, context.config);
1787        let g_shape = g_shape
1788            .offset_left(result.len())
1789            .and_then(|s| s.sub_width(2))
1790            .max_width_error(g_shape.width, span)?;
1791        let generics_str = rewrite_generics(context, ident_str, generics, g_shape)?;
1792        result.push_str(&generics_str);
1793    }
1794
1795    if let Some(bounds) = generic_bounds_opt {
1796        if !bounds.is_empty() {
1797            // 2 = `: `
1798            let shape = Shape::indented(indent, context.config);
1799            let shape = shape
1800                .offset_left(result.len() + 2)
1801                .max_width_error(shape.width, span)?;
1802            let type_bounds = bounds
1803                .rewrite_result(context, shape)
1804                .map(|s| format!(": {}", s))?;
1805            result.push_str(&type_bounds);
1806        }
1807    }
1808
1809    let where_budget = context.budget(last_line_width(&result));
1810    let mut option = WhereClauseOption::snuggled(&result);
1811    if rhs.is_none() {
1812        option.suppress_comma();
1813    }
1814    let before_where_clause_str = rewrite_where_clause(
1815        context,
1816        before_where_predicates,
1817        where_clauses.before.span,
1818        context.config.brace_style(),
1819        Shape::legacy(where_budget, indent),
1820        false,
1821        "=",
1822        None,
1823        generics.span.hi(),
1824        option,
1825    )?;
1826    result.push_str(&before_where_clause_str);
1827
1828    let mut result = if let Some(ty) = rhs {
1829        // If there are any where clauses, add a newline before the assignment.
1830        // If there is a before where clause, do not indent, but if there is
1831        // only an after where clause, additionally indent the type.
1832        if !before_where_predicates.is_empty() {
1833            result.push_str(&indent.to_string_with_newline(context.config));
1834        } else if !after_where_predicates.is_empty() {
1835            result.push_str(
1836                &indent
1837                    .block_indent(context.config)
1838                    .to_string_with_newline(context.config),
1839            );
1840        } else {
1841            result.push(' ');
1842        }
1843
1844        let comment_span = context
1845            .snippet_provider
1846            .opt_span_before(span, "=")
1847            .map(|op_lo| mk_sp(where_clauses.before.span.hi(), op_lo));
1848
1849        let lhs = match comment_span {
1850            Some(comment_span)
1851                if contains_comment(
1852                    context
1853                        .snippet_provider
1854                        .span_to_snippet(comment_span)
1855                        .unknown_error()?,
1856                ) =>
1857            {
1858                let comment_shape = if !before_where_predicates.is_empty() {
1859                    Shape::indented(indent, context.config)
1860                } else {
1861                    let shape = Shape::indented(indent, context.config);
1862                    shape
1863                        .block_left(context.config.tab_spaces())
1864                        .max_width_error(shape.width, span)?
1865                };
1866
1867                combine_strs_with_missing_comments(
1868                    context,
1869                    result.trim_end(),
1870                    "=",
1871                    comment_span,
1872                    comment_shape,
1873                    true,
1874                )?
1875            }
1876            _ => format!("{result}="),
1877        };
1878
1879        // 1 = `;` unless there's a trailing where clause
1880        let shape = Shape::indented(indent, context.config);
1881        let shape = if after_where_predicates.is_empty() {
1882            Shape::indented(indent, context.config)
1883                .sub_width(1)
1884                .max_width_error(shape.width, span)?
1885        } else {
1886            shape
1887        };
1888        rewrite_assign_rhs(context, lhs, &*ty, &RhsAssignKind::Ty, shape)?
1889    } else {
1890        result
1891    };
1892
1893    if !after_where_predicates.is_empty() {
1894        let option = WhereClauseOption::new(true, WhereClauseSpace::Newline);
1895        let after_where_clause_str = rewrite_where_clause(
1896            context,
1897            after_where_predicates,
1898            where_clauses.after.span,
1899            context.config.brace_style(),
1900            Shape::indented(indent, context.config),
1901            false,
1902            ";",
1903            None,
1904            rhs_hi,
1905            option,
1906        )?;
1907        result.push_str(&after_where_clause_str);
1908    }
1909
1910    result += ";";
1911    Ok(result)
1912}
1913
1914fn type_annotation_spacing(config: &Config) -> (&str, &str) {
1915    (
1916        if config.space_before_colon() { " " } else { "" },
1917        if config.space_after_colon() { " " } else { "" },
1918    )
1919}
1920
1921pub(crate) fn rewrite_struct_field_prefix(
1922    context: &RewriteContext<'_>,
1923    field: &ast::FieldDef,
1924) -> RewriteResult {
1925    let vis = format_visibility(context, &field.vis);
1926    let safety = format_safety(field.safety);
1927    let type_annotation_spacing = type_annotation_spacing(context.config);
1928    Ok(match field.ident {
1929        Some(name) => format!(
1930            "{vis}{safety}{}{}:",
1931            rewrite_ident(context, name),
1932            type_annotation_spacing.0
1933        ),
1934        None => format!("{vis}{safety}"),
1935    })
1936}
1937
1938impl Rewrite for ast::FieldDef {
1939    fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
1940        self.rewrite_result(context, shape).ok()
1941    }
1942
1943    fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult {
1944        rewrite_struct_field(context, self, shape, 0)
1945    }
1946}
1947
1948pub(crate) fn rewrite_struct_field(
1949    context: &RewriteContext<'_>,
1950    field: &ast::FieldDef,
1951    shape: Shape,
1952    lhs_max_width: usize,
1953) -> RewriteResult {
1954    // FIXME(default_field_values): Implement formatting.
1955    if field.default.is_some() {
1956        return Err(RewriteError::Unknown);
1957    }
1958
1959    if contains_skip(&field.attrs) {
1960        return Ok(context.snippet(field.span()).to_owned());
1961    }
1962
1963    let type_annotation_spacing = type_annotation_spacing(context.config);
1964    let prefix = rewrite_struct_field_prefix(context, field)?;
1965
1966    let attrs_str = field.attrs.rewrite_result(context, shape)?;
1967    let attrs_extendable = field.ident.is_none() && is_attributes_extendable(&attrs_str);
1968    let missing_span = if field.attrs.is_empty() {
1969        mk_sp(field.span.lo(), field.span.lo())
1970    } else {
1971        mk_sp(field.attrs.last().unwrap().span.hi(), field.span.lo())
1972    };
1973    let mut spacing = String::from(if field.ident.is_some() {
1974        type_annotation_spacing.1
1975    } else {
1976        ""
1977    });
1978    // Try to put everything on a single line.
1979    let attr_prefix = combine_strs_with_missing_comments(
1980        context,
1981        &attrs_str,
1982        &prefix,
1983        missing_span,
1984        shape,
1985        attrs_extendable,
1986    )?;
1987    let overhead = trimmed_last_line_width(&attr_prefix);
1988    let lhs_offset = lhs_max_width.saturating_sub(overhead);
1989    for _ in 0..lhs_offset {
1990        spacing.push(' ');
1991    }
1992    // In this extreme case we will be missing a space between an attribute and a field.
1993    if prefix.is_empty() && !attrs_str.is_empty() && attrs_extendable && spacing.is_empty() {
1994        spacing.push(' ');
1995    }
1996
1997    let orig_ty = shape
1998        .offset_left(overhead + spacing.len())
1999        .and_then(|ty_shape| field.ty.rewrite_result(context, ty_shape).ok());
2000
2001    if let Some(ref ty) = orig_ty {
2002        if !ty.contains('\n') && !contains_comment(context.snippet(missing_span)) {
2003            return Ok(attr_prefix + &spacing + ty);
2004        }
2005    }
2006
2007    let is_prefix_empty = prefix.is_empty();
2008    // We must use multiline. We are going to put attributes and a field on different lines.
2009    let field_str = rewrite_assign_rhs(context, prefix, &*field.ty, &RhsAssignKind::Ty, shape)?;
2010    // Remove a leading white-space from `rewrite_assign_rhs()` when rewriting a tuple struct.
2011    let field_str = if is_prefix_empty {
2012        field_str.trim_start()
2013    } else {
2014        &field_str
2015    };
2016    combine_strs_with_missing_comments(context, &attrs_str, field_str, missing_span, shape, false)
2017}
2018
2019pub(crate) struct StaticParts<'a> {
2020    prefix: &'a str,
2021    safety: ast::Safety,
2022    vis: &'a ast::Visibility,
2023    ident: symbol::Ident,
2024    generics: Option<&'a ast::Generics>,
2025    ty: &'a ast::Ty,
2026    mutability: ast::Mutability,
2027    expr_opt: Option<&'a ptr::P<ast::Expr>>,
2028    defaultness: Option<ast::Defaultness>,
2029    span: Span,
2030}
2031
2032impl<'a> StaticParts<'a> {
2033    pub(crate) fn from_item(item: &'a ast::Item) -> Self {
2034        let (defaultness, prefix, safety, ident, ty, mutability, expr, generics) = match &item.kind
2035        {
2036            ast::ItemKind::Static(s) => (
2037                None,
2038                "static",
2039                s.safety,
2040                s.ident,
2041                &s.ty,
2042                s.mutability,
2043                &s.expr,
2044                None,
2045            ),
2046            ast::ItemKind::Const(c) => (
2047                Some(c.defaultness),
2048                "const",
2049                ast::Safety::Default,
2050                c.ident,
2051                &c.ty,
2052                ast::Mutability::Not,
2053                &c.expr,
2054                Some(&c.generics),
2055            ),
2056            _ => unreachable!(),
2057        };
2058        StaticParts {
2059            prefix,
2060            safety,
2061            vis: &item.vis,
2062            ident,
2063            generics,
2064            ty,
2065            mutability,
2066            expr_opt: expr.as_ref(),
2067            defaultness,
2068            span: item.span,
2069        }
2070    }
2071
2072    pub(crate) fn from_trait_item(ti: &'a ast::AssocItem, ident: Ident) -> Self {
2073        let (defaultness, ty, expr_opt, generics) = match &ti.kind {
2074            ast::AssocItemKind::Const(c) => (c.defaultness, &c.ty, &c.expr, Some(&c.generics)),
2075            _ => unreachable!(),
2076        };
2077        StaticParts {
2078            prefix: "const",
2079            safety: ast::Safety::Default,
2080            vis: &ti.vis,
2081            ident,
2082            generics,
2083            ty,
2084            mutability: ast::Mutability::Not,
2085            expr_opt: expr_opt.as_ref(),
2086            defaultness: Some(defaultness),
2087            span: ti.span,
2088        }
2089    }
2090
2091    pub(crate) fn from_impl_item(ii: &'a ast::AssocItem, ident: Ident) -> Self {
2092        let (defaultness, ty, expr, generics) = match &ii.kind {
2093            ast::AssocItemKind::Const(c) => (c.defaultness, &c.ty, &c.expr, Some(&c.generics)),
2094            _ => unreachable!(),
2095        };
2096        StaticParts {
2097            prefix: "const",
2098            safety: ast::Safety::Default,
2099            vis: &ii.vis,
2100            ident,
2101            generics,
2102            ty,
2103            mutability: ast::Mutability::Not,
2104            expr_opt: expr.as_ref(),
2105            defaultness: Some(defaultness),
2106            span: ii.span,
2107        }
2108    }
2109}
2110
2111fn rewrite_static(
2112    context: &RewriteContext<'_>,
2113    static_parts: &StaticParts<'_>,
2114    offset: Indent,
2115) -> Option<String> {
2116    // For now, if this static (or const) has generics, then bail.
2117    if static_parts
2118        .generics
2119        .is_some_and(|g| !g.params.is_empty() || !g.where_clause.is_empty())
2120    {
2121        return None;
2122    }
2123
2124    let colon = colon_spaces(context.config);
2125    let mut prefix = format!(
2126        "{}{}{}{} {}{}{}",
2127        format_visibility(context, static_parts.vis),
2128        static_parts.defaultness.map_or("", format_defaultness),
2129        format_safety(static_parts.safety),
2130        static_parts.prefix,
2131        format_mutability(static_parts.mutability),
2132        rewrite_ident(context, static_parts.ident),
2133        colon,
2134    );
2135    // 2 = " =".len()
2136    let ty_shape =
2137        Shape::indented(offset.block_only(), context.config).offset_left(prefix.len() + 2)?;
2138    let ty_str = match static_parts.ty.rewrite(context, ty_shape) {
2139        Some(ty_str) => ty_str,
2140        None => {
2141            if prefix.ends_with(' ') {
2142                prefix.pop();
2143            }
2144            let nested_indent = offset.block_indent(context.config);
2145            let nested_shape = Shape::indented(nested_indent, context.config);
2146            let ty_str = static_parts.ty.rewrite(context, nested_shape)?;
2147            format!(
2148                "{}{}",
2149                nested_indent.to_string_with_newline(context.config),
2150                ty_str
2151            )
2152        }
2153    };
2154
2155    if let Some(expr) = static_parts.expr_opt {
2156        let comments_lo = context.snippet_provider.span_after(static_parts.span, "=");
2157        let expr_lo = expr.span.lo();
2158        let comments_span = mk_sp(comments_lo, expr_lo);
2159
2160        let lhs = format!("{prefix}{ty_str} =");
2161
2162        // 1 = ;
2163        let remaining_width = context.budget(offset.block_indent + 1);
2164        rewrite_assign_rhs_with_comments(
2165            context,
2166            &lhs,
2167            &**expr,
2168            Shape::legacy(remaining_width, offset.block_only()),
2169            &RhsAssignKind::Expr(&expr.kind, expr.span),
2170            RhsTactics::Default,
2171            comments_span,
2172            true,
2173        )
2174        .ok()
2175        .map(|res| recover_comment_removed(res, static_parts.span, context))
2176        .map(|s| if s.ends_with(';') { s } else { s + ";" })
2177    } else {
2178        Some(format!("{prefix}{ty_str};"))
2179    }
2180}
2181
2182// FIXME(calebcartwright) - This is a hack around a bug in the handling of TyKind::ImplTrait.
2183// This should be removed once that bug is resolved, with the type alias formatting using the
2184// defined Ty for the RHS directly.
2185// https://github.com/rust-lang/rustfmt/issues/4373
2186// https://github.com/rust-lang/rustfmt/issues/5027
2187struct OpaqueType<'a> {
2188    bounds: &'a ast::GenericBounds,
2189}
2190
2191impl<'a> Rewrite for OpaqueType<'a> {
2192    fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
2193        let shape = shape.offset_left(5)?; // `impl `
2194        self.bounds
2195            .rewrite(context, shape)
2196            .map(|s| format!("impl {}", s))
2197    }
2198}
2199
2200impl Rewrite for ast::FnRetTy {
2201    fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
2202        self.rewrite_result(context, shape).ok()
2203    }
2204
2205    fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult {
2206        match *self {
2207            ast::FnRetTy::Default(_) => Ok(String::new()),
2208            ast::FnRetTy::Ty(ref ty) => {
2209                let arrow_width = "-> ".len();
2210                if context.config.style_edition() <= StyleEdition::Edition2021
2211                    || context.config.indent_style() == IndentStyle::Visual
2212                {
2213                    let inner_width = shape
2214                        .width
2215                        .checked_sub(arrow_width)
2216                        .max_width_error(shape.width, self.span())?;
2217                    return ty
2218                        .rewrite_result(
2219                            context,
2220                            Shape::legacy(inner_width, shape.indent + arrow_width),
2221                        )
2222                        .map(|r| format!("-> {}", r));
2223                }
2224
2225                let shape = shape
2226                    .offset_left(arrow_width)
2227                    .max_width_error(shape.width, self.span())?;
2228
2229                ty.rewrite_result(context, shape)
2230                    .map(|s| format!("-> {}", s))
2231            }
2232        }
2233    }
2234}
2235
2236fn is_empty_infer(ty: &ast::Ty, pat_span: Span) -> bool {
2237    match ty.kind {
2238        ast::TyKind::Infer => ty.span.hi() == pat_span.hi(),
2239        _ => false,
2240    }
2241}
2242
2243/// Recover any missing comments between the param and the type.
2244///
2245/// # Returns
2246///
2247/// A 2-len tuple with the comment before the colon in first position, and the comment after the
2248/// colon in second position.
2249fn get_missing_param_comments(
2250    context: &RewriteContext<'_>,
2251    pat_span: Span,
2252    ty_span: Span,
2253    shape: Shape,
2254) -> (String, String) {
2255    let missing_comment_span = mk_sp(pat_span.hi(), ty_span.lo());
2256
2257    let span_before_colon = {
2258        let missing_comment_span_hi = context
2259            .snippet_provider
2260            .span_before(missing_comment_span, ":");
2261        mk_sp(pat_span.hi(), missing_comment_span_hi)
2262    };
2263    let span_after_colon = {
2264        let missing_comment_span_lo = context
2265            .snippet_provider
2266            .span_after(missing_comment_span, ":");
2267        mk_sp(missing_comment_span_lo, ty_span.lo())
2268    };
2269
2270    let comment_before_colon = rewrite_missing_comment(span_before_colon, shape, context)
2271        .ok()
2272        .filter(|comment| !comment.is_empty())
2273        .map_or(String::new(), |comment| format!(" {}", comment));
2274    let comment_after_colon = rewrite_missing_comment(span_after_colon, shape, context)
2275        .ok()
2276        .filter(|comment| !comment.is_empty())
2277        .map_or(String::new(), |comment| format!("{} ", comment));
2278    (comment_before_colon, comment_after_colon)
2279}
2280
2281impl Rewrite for ast::Param {
2282    fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
2283        self.rewrite_result(context, shape).ok()
2284    }
2285
2286    fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult {
2287        let param_attrs_result = self
2288            .attrs
2289            .rewrite_result(context, Shape::legacy(shape.width, shape.indent))?;
2290        // N.B. Doc comments aren't typically valid syntax, but could appear
2291        // in the presence of certain macros - https://github.com/rust-lang/rustfmt/issues/4936
2292        let (span, has_multiple_attr_lines, has_doc_comments) = if !self.attrs.is_empty() {
2293            let num_attrs = self.attrs.len();
2294            (
2295                mk_sp(self.attrs[num_attrs - 1].span.hi(), self.pat.span.lo()),
2296                param_attrs_result.contains('\n'),
2297                self.attrs.iter().any(|a| a.is_doc_comment()),
2298            )
2299        } else {
2300            (mk_sp(self.span.lo(), self.span.lo()), false, false)
2301        };
2302
2303        if let Some(ref explicit_self) = self.to_self() {
2304            rewrite_explicit_self(
2305                context,
2306                explicit_self,
2307                &param_attrs_result,
2308                span,
2309                shape,
2310                has_multiple_attr_lines,
2311            )
2312        } else if is_named_param(self) {
2313            let param_name = &self
2314                .pat
2315                .rewrite_result(context, Shape::legacy(shape.width, shape.indent))?;
2316            let mut result = combine_strs_with_missing_comments(
2317                context,
2318                &param_attrs_result,
2319                param_name,
2320                span,
2321                shape,
2322                !has_multiple_attr_lines && !has_doc_comments,
2323            )?;
2324
2325            if !is_empty_infer(&*self.ty, self.pat.span) {
2326                let (before_comment, after_comment) =
2327                    get_missing_param_comments(context, self.pat.span, self.ty.span, shape);
2328                result.push_str(&before_comment);
2329                result.push_str(colon_spaces(context.config));
2330                result.push_str(&after_comment);
2331                let overhead = last_line_width(&result);
2332                let max_width = shape
2333                    .width
2334                    .checked_sub(overhead)
2335                    .max_width_error(shape.width, self.span())?;
2336                if let Ok(ty_str) = self
2337                    .ty
2338                    .rewrite_result(context, Shape::legacy(max_width, shape.indent))
2339                {
2340                    result.push_str(&ty_str);
2341                } else {
2342                    let prev_str = if param_attrs_result.is_empty() {
2343                        param_attrs_result
2344                    } else {
2345                        param_attrs_result + &shape.to_string_with_newline(context.config)
2346                    };
2347
2348                    result = combine_strs_with_missing_comments(
2349                        context,
2350                        &prev_str,
2351                        param_name,
2352                        span,
2353                        shape,
2354                        !has_multiple_attr_lines,
2355                    )?;
2356                    result.push_str(&before_comment);
2357                    result.push_str(colon_spaces(context.config));
2358                    result.push_str(&after_comment);
2359                    let overhead = last_line_width(&result);
2360                    let max_width = shape
2361                        .width
2362                        .checked_sub(overhead)
2363                        .max_width_error(shape.width, self.span())?;
2364                    let ty_str = self
2365                        .ty
2366                        .rewrite_result(context, Shape::legacy(max_width, shape.indent))?;
2367                    result.push_str(&ty_str);
2368                }
2369            }
2370
2371            Ok(result)
2372        } else {
2373            self.ty.rewrite_result(context, shape)
2374        }
2375    }
2376}
2377
2378fn rewrite_opt_lifetime(
2379    context: &RewriteContext<'_>,
2380    lifetime: Option<ast::Lifetime>,
2381) -> RewriteResult {
2382    let Some(l) = lifetime else {
2383        return Ok(String::new());
2384    };
2385    let mut result = l.rewrite_result(
2386        context,
2387        Shape::legacy(context.config.max_width(), Indent::empty()),
2388    )?;
2389    result.push(' ');
2390    Ok(result)
2391}
2392
2393fn rewrite_explicit_self(
2394    context: &RewriteContext<'_>,
2395    explicit_self: &ast::ExplicitSelf,
2396    param_attrs: &str,
2397    span: Span,
2398    shape: Shape,
2399    has_multiple_attr_lines: bool,
2400) -> RewriteResult {
2401    let self_str = match explicit_self.node {
2402        ast::SelfKind::Region(lt, m) => {
2403            let mut_str = format_mutability(m);
2404            let lifetime_str = rewrite_opt_lifetime(context, lt)?;
2405            format!("&{lifetime_str}{mut_str}self")
2406        }
2407        ast::SelfKind::Pinned(lt, m) => {
2408            let mut_str = m.ptr_str();
2409            let lifetime_str = rewrite_opt_lifetime(context, lt)?;
2410            format!("&{lifetime_str}pin {mut_str} self")
2411        }
2412        ast::SelfKind::Explicit(ref ty, mutability) => {
2413            let type_str = ty.rewrite_result(
2414                context,
2415                Shape::legacy(context.config.max_width(), Indent::empty()),
2416            )?;
2417            format!("{}self: {}", format_mutability(mutability), type_str)
2418        }
2419        ast::SelfKind::Value(mutability) => format!("{}self", format_mutability(mutability)),
2420    };
2421    Ok(combine_strs_with_missing_comments(
2422        context,
2423        param_attrs,
2424        &self_str,
2425        span,
2426        shape,
2427        !has_multiple_attr_lines,
2428    )?)
2429}
2430
2431pub(crate) fn span_lo_for_param(param: &ast::Param) -> BytePos {
2432    if param.attrs.is_empty() {
2433        if is_named_param(param) {
2434            param.pat.span.lo()
2435        } else {
2436            param.ty.span.lo()
2437        }
2438    } else {
2439        param.attrs[0].span.lo()
2440    }
2441}
2442
2443pub(crate) fn span_hi_for_param(context: &RewriteContext<'_>, param: &ast::Param) -> BytePos {
2444    match param.ty.kind {
2445        ast::TyKind::Infer if context.snippet(param.ty.span) == "_" => param.ty.span.hi(),
2446        ast::TyKind::Infer if is_named_param(param) => param.pat.span.hi(),
2447        _ => param.ty.span.hi(),
2448    }
2449}
2450
2451pub(crate) fn is_named_param(param: &ast::Param) -> bool {
2452    !matches!(param.pat.kind, ast::PatKind::Missing)
2453}
2454
2455#[derive(Copy, Clone, Debug, PartialEq, Eq)]
2456pub(crate) enum FnBraceStyle {
2457    SameLine,
2458    NextLine,
2459    None,
2460}
2461
2462// Return type is (result, force_new_line_for_brace)
2463fn rewrite_fn_base(
2464    context: &RewriteContext<'_>,
2465    indent: Indent,
2466    ident: symbol::Ident,
2467    fn_sig: &FnSig<'_>,
2468    span: Span,
2469    fn_brace_style: FnBraceStyle,
2470) -> Result<(String, bool, bool), RewriteError> {
2471    let mut force_new_line_for_brace = false;
2472
2473    let where_clause = &fn_sig.generics.where_clause;
2474
2475    let mut result = String::with_capacity(1024);
2476    result.push_str(&fn_sig.to_str(context));
2477
2478    // fn foo
2479    result.push_str("fn ");
2480
2481    // Generics.
2482    let overhead = if let FnBraceStyle::SameLine = fn_brace_style {
2483        // 4 = `() {`
2484        4
2485    } else {
2486        // 2 = `()`
2487        2
2488    };
2489    let used_width = last_line_used_width(&result, indent.width());
2490    let one_line_budget = context.budget(used_width + overhead);
2491    let shape = Shape {
2492        width: one_line_budget,
2493        indent,
2494        offset: used_width,
2495    };
2496    let fd = fn_sig.decl;
2497    let generics_str = rewrite_generics(
2498        context,
2499        rewrite_ident(context, ident),
2500        &fn_sig.generics,
2501        shape,
2502    )?;
2503    result.push_str(&generics_str);
2504
2505    let snuggle_angle_bracket = generics_str
2506        .lines()
2507        .last()
2508        .map_or(false, |l| l.trim_start().len() == 1);
2509
2510    // Note that the width and indent don't really matter, we'll re-layout the
2511    // return type later anyway.
2512    let ret_str = fd
2513        .output
2514        .rewrite_result(context, Shape::indented(indent, context.config))?;
2515
2516    let multi_line_ret_str = ret_str.contains('\n');
2517    let ret_str_len = if multi_line_ret_str { 0 } else { ret_str.len() };
2518
2519    // Params.
2520    let (one_line_budget, multi_line_budget, mut param_indent) = compute_budgets_for_params(
2521        context,
2522        &result,
2523        indent,
2524        ret_str_len,
2525        fn_brace_style,
2526        multi_line_ret_str,
2527    );
2528
2529    debug!(
2530        "rewrite_fn_base: one_line_budget: {}, multi_line_budget: {}, param_indent: {:?}",
2531        one_line_budget, multi_line_budget, param_indent
2532    );
2533
2534    result.push('(');
2535    // Check if vertical layout was forced.
2536    if one_line_budget == 0
2537        && !snuggle_angle_bracket
2538        && context.config.indent_style() == IndentStyle::Visual
2539    {
2540        result.push_str(&param_indent.to_string_with_newline(context.config));
2541    }
2542
2543    let params_end = if fd.inputs.is_empty() {
2544        context
2545            .snippet_provider
2546            .span_after(mk_sp(fn_sig.generics.span.hi(), span.hi()), ")")
2547    } else {
2548        let last_span = mk_sp(fd.inputs[fd.inputs.len() - 1].span().hi(), span.hi());
2549        context.snippet_provider.span_after(last_span, ")")
2550    };
2551    let params_span = mk_sp(
2552        context
2553            .snippet_provider
2554            .span_after(mk_sp(fn_sig.generics.span.hi(), span.hi()), "("),
2555        params_end,
2556    );
2557    let param_str = rewrite_params(
2558        context,
2559        &fd.inputs,
2560        one_line_budget,
2561        multi_line_budget,
2562        indent,
2563        param_indent,
2564        params_span,
2565        fd.c_variadic(),
2566    )?;
2567
2568    let put_params_in_block = match context.config.indent_style() {
2569        IndentStyle::Block => param_str.contains('\n') || param_str.len() > one_line_budget,
2570        _ => false,
2571    } && !fd.inputs.is_empty();
2572
2573    let mut params_last_line_contains_comment = false;
2574    let mut no_params_and_over_max_width = false;
2575
2576    if put_params_in_block {
2577        param_indent = indent.block_indent(context.config);
2578        result.push_str(&param_indent.to_string_with_newline(context.config));
2579        result.push_str(&param_str);
2580        result.push_str(&indent.to_string_with_newline(context.config));
2581        result.push(')');
2582    } else {
2583        result.push_str(&param_str);
2584        let used_width = last_line_used_width(&result, indent.width()) + first_line_width(&ret_str);
2585        // Put the closing brace on the next line if it overflows the max width.
2586        // 1 = `)`
2587        let closing_paren_overflow_max_width =
2588            fd.inputs.is_empty() && used_width + 1 > context.config.max_width();
2589        // If the last line of params contains comment, we cannot put the closing paren
2590        // on the same line.
2591        params_last_line_contains_comment = param_str
2592            .lines()
2593            .last()
2594            .map_or(false, |last_line| last_line.contains("//"));
2595
2596        if context.config.style_edition() >= StyleEdition::Edition2024 {
2597            if closing_paren_overflow_max_width {
2598                result.push(')');
2599                result.push_str(&indent.to_string_with_newline(context.config));
2600                no_params_and_over_max_width = true;
2601            } else if params_last_line_contains_comment {
2602                result.push_str(&indent.to_string_with_newline(context.config));
2603                result.push(')');
2604                no_params_and_over_max_width = true;
2605            } else {
2606                result.push(')');
2607            }
2608        } else {
2609            if closing_paren_overflow_max_width || params_last_line_contains_comment {
2610                result.push_str(&indent.to_string_with_newline(context.config));
2611            }
2612            result.push(')');
2613        }
2614    }
2615
2616    // Return type.
2617    if let ast::FnRetTy::Ty(..) = fd.output {
2618        let ret_should_indent = match context.config.indent_style() {
2619            // If our params are block layout then we surely must have space.
2620            IndentStyle::Block if put_params_in_block || fd.inputs.is_empty() => false,
2621            _ if params_last_line_contains_comment => false,
2622            _ if result.contains('\n') || multi_line_ret_str => true,
2623            _ => {
2624                // If the return type would push over the max width, then put the return type on
2625                // a new line. With the +1 for the signature length an additional space between
2626                // the closing parenthesis of the param and the arrow '->' is considered.
2627                let mut sig_length = result.len() + indent.width() + ret_str_len + 1;
2628
2629                // If there is no where-clause, take into account the space after the return type
2630                // and the brace.
2631                if where_clause.predicates.is_empty() {
2632                    sig_length += 2;
2633                }
2634
2635                sig_length > context.config.max_width()
2636            }
2637        };
2638        let ret_shape = if ret_should_indent {
2639            if context.config.style_edition() <= StyleEdition::Edition2021
2640                || context.config.indent_style() == IndentStyle::Visual
2641            {
2642                let indent = if param_str.is_empty() {
2643                    // Aligning with nonexistent params looks silly.
2644                    force_new_line_for_brace = true;
2645                    indent + 4
2646                } else {
2647                    // FIXME: we might want to check that using the param indent
2648                    // doesn't blow our budget, and if it does, then fallback to
2649                    // the where-clause indent.
2650                    param_indent
2651                };
2652
2653                result.push_str(&indent.to_string_with_newline(context.config));
2654                Shape::indented(indent, context.config)
2655            } else {
2656                let mut ret_shape = Shape::indented(indent, context.config);
2657                if param_str.is_empty() {
2658                    // Aligning with nonexistent params looks silly.
2659                    force_new_line_for_brace = true;
2660                    ret_shape = if context.use_block_indent() {
2661                        ret_shape.offset_left(4).unwrap_or(ret_shape)
2662                    } else {
2663                        ret_shape.indent = ret_shape.indent + 4;
2664                        ret_shape
2665                    };
2666                }
2667
2668                result.push_str(&ret_shape.indent.to_string_with_newline(context.config));
2669                ret_shape
2670            }
2671        } else {
2672            if context.config.style_edition() >= StyleEdition::Edition2024 {
2673                if !param_str.is_empty() || !no_params_and_over_max_width {
2674                    result.push(' ');
2675                }
2676            } else {
2677                result.push(' ');
2678            }
2679
2680            let ret_shape = Shape::indented(indent, context.config);
2681            ret_shape
2682                .offset_left(last_line_width(&result))
2683                .unwrap_or(ret_shape)
2684        };
2685
2686        if multi_line_ret_str || ret_should_indent {
2687            // Now that we know the proper indent and width, we need to
2688            // re-layout the return type.
2689            let ret_str = fd.output.rewrite_result(context, ret_shape)?;
2690            result.push_str(&ret_str);
2691        } else {
2692            result.push_str(&ret_str);
2693        }
2694
2695        // Comment between return type and the end of the decl.
2696        let snippet_lo = fd.output.span().hi();
2697        if where_clause.predicates.is_empty() {
2698            let snippet_hi = span.hi();
2699            let snippet = context.snippet(mk_sp(snippet_lo, snippet_hi));
2700            // Try to preserve the layout of the original snippet.
2701            let original_starts_with_newline = snippet
2702                .find(|c| c != ' ')
2703                .map_or(false, |i| starts_with_newline(&snippet[i..]));
2704            let original_ends_with_newline = snippet
2705                .rfind(|c| c != ' ')
2706                .map_or(false, |i| snippet[i..].ends_with('\n'));
2707            let snippet = snippet.trim();
2708            if !snippet.is_empty() {
2709                result.push(if original_starts_with_newline {
2710                    '\n'
2711                } else {
2712                    ' '
2713                });
2714                result.push_str(snippet);
2715                if original_ends_with_newline {
2716                    force_new_line_for_brace = true;
2717                }
2718            }
2719        }
2720    }
2721
2722    let pos_before_where = match fd.output {
2723        ast::FnRetTy::Default(..) => params_span.hi(),
2724        ast::FnRetTy::Ty(ref ty) => ty.span.hi(),
2725    };
2726
2727    let is_params_multi_lined = param_str.contains('\n');
2728
2729    let space = if put_params_in_block && ret_str.is_empty() {
2730        WhereClauseSpace::Space
2731    } else {
2732        WhereClauseSpace::Newline
2733    };
2734    let mut option = WhereClauseOption::new(fn_brace_style == FnBraceStyle::None, space);
2735    if is_params_multi_lined {
2736        option.veto_single_line();
2737    }
2738    let where_clause_str = rewrite_where_clause(
2739        context,
2740        &where_clause.predicates,
2741        where_clause.span,
2742        context.config.brace_style(),
2743        Shape::indented(indent, context.config),
2744        true,
2745        "{",
2746        Some(span.hi()),
2747        pos_before_where,
2748        option,
2749    )?;
2750    // If there are neither where-clause nor return type, we may be missing comments between
2751    // params and `{`.
2752    if where_clause_str.is_empty() {
2753        if let ast::FnRetTy::Default(ret_span) = fd.output {
2754            match recover_missing_comment_in_span(
2755                // from after the closing paren to right before block or semicolon
2756                mk_sp(ret_span.lo(), span.hi()),
2757                shape,
2758                context,
2759                last_line_width(&result),
2760            ) {
2761                Ok(ref missing_comment) if !missing_comment.is_empty() => {
2762                    result.push_str(missing_comment);
2763                    force_new_line_for_brace = true;
2764                }
2765                _ => (),
2766            }
2767        }
2768    }
2769
2770    result.push_str(&where_clause_str);
2771
2772    let ends_with_comment = last_line_contains_single_line_comment(&result);
2773    force_new_line_for_brace |= ends_with_comment;
2774    force_new_line_for_brace |=
2775        is_params_multi_lined && context.config.where_single_line() && !where_clause_str.is_empty();
2776    Ok((result, ends_with_comment, force_new_line_for_brace))
2777}
2778
2779/// Kind of spaces to put before `where`.
2780#[derive(Copy, Clone)]
2781enum WhereClauseSpace {
2782    /// A single space.
2783    Space,
2784    /// A new line.
2785    Newline,
2786    /// Nothing.
2787    None,
2788}
2789
2790#[derive(Copy, Clone)]
2791struct WhereClauseOption {
2792    suppress_comma: bool, // Force no trailing comma
2793    snuggle: WhereClauseSpace,
2794    allow_single_line: bool, // Try single line where-clause instead of vertical layout
2795    veto_single_line: bool,  // Disallow a single-line where-clause.
2796}
2797
2798impl WhereClauseOption {
2799    fn new(suppress_comma: bool, snuggle: WhereClauseSpace) -> WhereClauseOption {
2800        WhereClauseOption {
2801            suppress_comma,
2802            snuggle,
2803            allow_single_line: false,
2804            veto_single_line: false,
2805        }
2806    }
2807
2808    fn snuggled(current: &str) -> WhereClauseOption {
2809        WhereClauseOption {
2810            suppress_comma: false,
2811            snuggle: if last_line_width(current) == 1 {
2812                WhereClauseSpace::Space
2813            } else {
2814                WhereClauseSpace::Newline
2815            },
2816            allow_single_line: false,
2817            veto_single_line: false,
2818        }
2819    }
2820
2821    fn suppress_comma(&mut self) {
2822        self.suppress_comma = true
2823    }
2824
2825    fn allow_single_line(&mut self) {
2826        self.allow_single_line = true
2827    }
2828
2829    fn snuggle(&mut self) {
2830        self.snuggle = WhereClauseSpace::Space
2831    }
2832
2833    fn veto_single_line(&mut self) {
2834        self.veto_single_line = true;
2835    }
2836}
2837
2838fn rewrite_params(
2839    context: &RewriteContext<'_>,
2840    params: &[ast::Param],
2841    one_line_budget: usize,
2842    multi_line_budget: usize,
2843    indent: Indent,
2844    param_indent: Indent,
2845    span: Span,
2846    variadic: bool,
2847) -> RewriteResult {
2848    if params.is_empty() {
2849        let comment = context
2850            .snippet(mk_sp(
2851                span.lo(),
2852                // to remove ')'
2853                span.hi() - BytePos(1),
2854            ))
2855            .trim();
2856        return Ok(comment.to_owned());
2857    }
2858    let param_items: Vec<_> = itemize_list(
2859        context.snippet_provider,
2860        params.iter(),
2861        ")",
2862        ",",
2863        |param| span_lo_for_param(param),
2864        |param| param.ty.span.hi(),
2865        |param| {
2866            param
2867                .rewrite_result(context, Shape::legacy(multi_line_budget, param_indent))
2868                .or_else(|_| Ok(context.snippet(param.span()).to_owned()))
2869        },
2870        span.lo(),
2871        span.hi(),
2872        false,
2873    )
2874    .collect();
2875
2876    let tactic = definitive_tactic(
2877        &param_items,
2878        context
2879            .config
2880            .fn_params_layout()
2881            .to_list_tactic(param_items.len()),
2882        Separator::Comma,
2883        one_line_budget,
2884    );
2885    let budget = match tactic {
2886        DefinitiveListTactic::Horizontal => one_line_budget,
2887        _ => multi_line_budget,
2888    };
2889    let indent = match context.config.indent_style() {
2890        IndentStyle::Block => indent.block_indent(context.config),
2891        IndentStyle::Visual => param_indent,
2892    };
2893    let trailing_separator = if variadic {
2894        SeparatorTactic::Never
2895    } else {
2896        match context.config.indent_style() {
2897            IndentStyle::Block => context.config.trailing_comma(),
2898            IndentStyle::Visual => SeparatorTactic::Never,
2899        }
2900    };
2901    let fmt = ListFormatting::new(Shape::legacy(budget, indent), context.config)
2902        .tactic(tactic)
2903        .trailing_separator(trailing_separator)
2904        .ends_with_newline(tactic.ends_with_newline(context.config.indent_style()))
2905        .preserve_newline(true);
2906    write_list(&param_items, &fmt)
2907}
2908
2909fn compute_budgets_for_params(
2910    context: &RewriteContext<'_>,
2911    result: &str,
2912    indent: Indent,
2913    ret_str_len: usize,
2914    fn_brace_style: FnBraceStyle,
2915    force_vertical_layout: bool,
2916) -> (usize, usize, Indent) {
2917    debug!(
2918        "compute_budgets_for_params {} {:?}, {}, {:?}",
2919        result.len(),
2920        indent,
2921        ret_str_len,
2922        fn_brace_style,
2923    );
2924    // Try keeping everything on the same line.
2925    if !result.contains('\n') && !force_vertical_layout {
2926        // 2 = `()`, 3 = `() `, space is before ret_string.
2927        let overhead = if ret_str_len == 0 { 2 } else { 3 };
2928        let mut used_space = indent.width() + result.len() + ret_str_len + overhead;
2929        match fn_brace_style {
2930            FnBraceStyle::None => used_space += 1,     // 1 = `;`
2931            FnBraceStyle::SameLine => used_space += 2, // 2 = `{}`
2932            FnBraceStyle::NextLine => (),
2933        }
2934        let one_line_budget = context.budget(used_space);
2935
2936        if one_line_budget > 0 {
2937            // 4 = "() {".len()
2938            let (indent, multi_line_budget) = match context.config.indent_style() {
2939                IndentStyle::Block => {
2940                    let indent = indent.block_indent(context.config);
2941                    (indent, context.budget(indent.width() + 1))
2942                }
2943                IndentStyle::Visual => {
2944                    let indent = indent + result.len() + 1;
2945                    let multi_line_overhead = match fn_brace_style {
2946                        FnBraceStyle::SameLine => 4,
2947                        _ => 2,
2948                    } + indent.width();
2949                    (indent, context.budget(multi_line_overhead))
2950                }
2951            };
2952
2953            return (one_line_budget, multi_line_budget, indent);
2954        }
2955    }
2956
2957    // Didn't work. we must force vertical layout and put params on a newline.
2958    let new_indent = indent.block_indent(context.config);
2959    let used_space = match context.config.indent_style() {
2960        // 1 = `,`
2961        IndentStyle::Block => new_indent.width() + 1,
2962        // Account for `)` and possibly ` {`.
2963        IndentStyle::Visual => new_indent.width() + if ret_str_len == 0 { 1 } else { 3 },
2964    };
2965    (0, context.budget(used_space), new_indent)
2966}
2967
2968fn newline_for_brace(config: &Config, where_clause: &ast::WhereClause) -> FnBraceStyle {
2969    let predicate_count = where_clause.predicates.len();
2970
2971    if config.where_single_line() && predicate_count == 1 {
2972        return FnBraceStyle::SameLine;
2973    }
2974    let brace_style = config.brace_style();
2975
2976    let use_next_line = brace_style == BraceStyle::AlwaysNextLine
2977        || (brace_style == BraceStyle::SameLineWhere && predicate_count > 0);
2978    if use_next_line {
2979        FnBraceStyle::NextLine
2980    } else {
2981        FnBraceStyle::SameLine
2982    }
2983}
2984
2985fn rewrite_generics(
2986    context: &RewriteContext<'_>,
2987    ident: &str,
2988    generics: &ast::Generics,
2989    shape: Shape,
2990) -> RewriteResult {
2991    // FIXME: convert bounds to where-clauses where they get too big or if
2992    // there is a where-clause at all.
2993
2994    if generics.params.is_empty() {
2995        return Ok(ident.to_owned());
2996    }
2997
2998    let params = generics.params.iter();
2999    overflow::rewrite_with_angle_brackets(context, ident, params, shape, generics.span)
3000}
3001
3002fn generics_shape_from_config(config: &Config, shape: Shape, offset: usize) -> Option<Shape> {
3003    match config.indent_style() {
3004        IndentStyle::Visual => shape.visual_indent(1 + offset).sub_width(offset + 2),
3005        IndentStyle::Block => {
3006            // 1 = ","
3007            shape
3008                .block()
3009                .block_indent(config.tab_spaces())
3010                .with_max_width(config)
3011                .sub_width(1)
3012        }
3013    }
3014}
3015
3016fn rewrite_where_clause_rfc_style(
3017    context: &RewriteContext<'_>,
3018    predicates: &[ast::WherePredicate],
3019    where_span: Span,
3020    shape: Shape,
3021    terminator: &str,
3022    span_end: Option<BytePos>,
3023    span_end_before_where: BytePos,
3024    where_clause_option: WhereClauseOption,
3025) -> RewriteResult {
3026    let (where_keyword, allow_single_line) = rewrite_where_keyword(
3027        context,
3028        predicates,
3029        where_span,
3030        shape,
3031        span_end_before_where,
3032        where_clause_option,
3033    )?;
3034
3035    // 1 = `,`
3036    let clause_shape = shape
3037        .block()
3038        .with_max_width(context.config)
3039        .block_left(context.config.tab_spaces())
3040        .and_then(|s| s.sub_width(1))
3041        .max_width_error(shape.width, where_span)?;
3042    let force_single_line = context.config.where_single_line()
3043        && predicates.len() == 1
3044        && !where_clause_option.veto_single_line;
3045
3046    let preds_str = rewrite_bounds_on_where_clause(
3047        context,
3048        predicates,
3049        clause_shape,
3050        terminator,
3051        span_end,
3052        where_clause_option,
3053        force_single_line,
3054    )?;
3055
3056    // 6 = `where `
3057    let clause_sep =
3058        if allow_single_line && !preds_str.contains('\n') && 6 + preds_str.len() <= shape.width
3059            || force_single_line
3060        {
3061            Cow::from(" ")
3062        } else {
3063            clause_shape.indent.to_string_with_newline(context.config)
3064        };
3065
3066    Ok(format!("{where_keyword}{clause_sep}{preds_str}"))
3067}
3068
3069/// Rewrite `where` and comment around it.
3070fn rewrite_where_keyword(
3071    context: &RewriteContext<'_>,
3072    predicates: &[ast::WherePredicate],
3073    where_span: Span,
3074    shape: Shape,
3075    span_end_before_where: BytePos,
3076    where_clause_option: WhereClauseOption,
3077) -> Result<(String, bool), RewriteError> {
3078    let block_shape = shape.block().with_max_width(context.config);
3079    // 1 = `,`
3080    let clause_shape = block_shape
3081        .block_left(context.config.tab_spaces())
3082        .and_then(|s| s.sub_width(1))
3083        .max_width_error(block_shape.width, where_span)?;
3084
3085    let comment_separator = |comment: &str, shape: Shape| {
3086        if comment.is_empty() {
3087            Cow::from("")
3088        } else {
3089            shape.indent.to_string_with_newline(context.config)
3090        }
3091    };
3092
3093    let (span_before, span_after) =
3094        missing_span_before_after_where(span_end_before_where, predicates, where_span);
3095    let (comment_before, comment_after) =
3096        rewrite_comments_before_after_where(context, span_before, span_after, shape)?;
3097
3098    let starting_newline = match where_clause_option.snuggle {
3099        WhereClauseSpace::Space if comment_before.is_empty() => Cow::from(" "),
3100        WhereClauseSpace::None => Cow::from(""),
3101        _ => block_shape.indent.to_string_with_newline(context.config),
3102    };
3103
3104    let newline_before_where = comment_separator(&comment_before, shape);
3105    let newline_after_where = comment_separator(&comment_after, clause_shape);
3106    let result = format!(
3107        "{starting_newline}{comment_before}{newline_before_where}where\
3108{newline_after_where}{comment_after}"
3109    );
3110    let allow_single_line = where_clause_option.allow_single_line
3111        && comment_before.is_empty()
3112        && comment_after.is_empty();
3113
3114    Ok((result, allow_single_line))
3115}
3116
3117/// Rewrite bounds on a where clause.
3118fn rewrite_bounds_on_where_clause(
3119    context: &RewriteContext<'_>,
3120    predicates: &[ast::WherePredicate],
3121    shape: Shape,
3122    terminator: &str,
3123    span_end: Option<BytePos>,
3124    where_clause_option: WhereClauseOption,
3125    force_single_line: bool,
3126) -> RewriteResult {
3127    let span_start = predicates[0].span().lo();
3128    // If we don't have the start of the next span, then use the end of the
3129    // predicates, but that means we miss comments.
3130    let len = predicates.len();
3131    let end_of_preds = predicates[len - 1].span().hi();
3132    let span_end = span_end.unwrap_or(end_of_preds);
3133    let items = itemize_list(
3134        context.snippet_provider,
3135        predicates.iter(),
3136        terminator,
3137        ",",
3138        |pred| pred.span().lo(),
3139        |pred| pred.span().hi(),
3140        |pred| pred.rewrite_result(context, shape),
3141        span_start,
3142        span_end,
3143        false,
3144    );
3145    let comma_tactic = if where_clause_option.suppress_comma || force_single_line {
3146        SeparatorTactic::Never
3147    } else {
3148        context.config.trailing_comma()
3149    };
3150
3151    // shape should be vertical only and only if we have `force_single_line` option enabled
3152    // and the number of items of the where-clause is equal to 1
3153    let shape_tactic = if force_single_line {
3154        DefinitiveListTactic::Horizontal
3155    } else {
3156        DefinitiveListTactic::Vertical
3157    };
3158
3159    let preserve_newline = context.config.style_edition() <= StyleEdition::Edition2021;
3160
3161    let fmt = ListFormatting::new(shape, context.config)
3162        .tactic(shape_tactic)
3163        .trailing_separator(comma_tactic)
3164        .preserve_newline(preserve_newline);
3165    write_list(&items.collect::<Vec<_>>(), &fmt)
3166}
3167
3168fn rewrite_where_clause(
3169    context: &RewriteContext<'_>,
3170    predicates: &[ast::WherePredicate],
3171    where_span: Span,
3172    brace_style: BraceStyle,
3173    shape: Shape,
3174    on_new_line: bool,
3175    terminator: &str,
3176    span_end: Option<BytePos>,
3177    span_end_before_where: BytePos,
3178    where_clause_option: WhereClauseOption,
3179) -> RewriteResult {
3180    if predicates.is_empty() {
3181        return Ok(String::new());
3182    }
3183
3184    if context.config.indent_style() == IndentStyle::Block {
3185        return rewrite_where_clause_rfc_style(
3186            context,
3187            predicates,
3188            where_span,
3189            shape,
3190            terminator,
3191            span_end,
3192            span_end_before_where,
3193            where_clause_option,
3194        );
3195    }
3196
3197    let extra_indent = Indent::new(context.config.tab_spaces(), 0);
3198
3199    let offset = match context.config.indent_style() {
3200        IndentStyle::Block => shape.indent + extra_indent.block_indent(context.config),
3201        // 6 = "where ".len()
3202        IndentStyle::Visual => shape.indent + extra_indent + 6,
3203    };
3204    // FIXME: if indent_style != Visual, then the budgets below might
3205    // be out by a char or two.
3206
3207    let budget = context.config.max_width() - offset.width();
3208    let span_start = predicates[0].span().lo();
3209    // If we don't have the start of the next span, then use the end of the
3210    // predicates, but that means we miss comments.
3211    let len = predicates.len();
3212    let end_of_preds = predicates[len - 1].span().hi();
3213    let span_end = span_end.unwrap_or(end_of_preds);
3214    let items = itemize_list(
3215        context.snippet_provider,
3216        predicates.iter(),
3217        terminator,
3218        ",",
3219        |pred| pred.span().lo(),
3220        |pred| pred.span().hi(),
3221        |pred| pred.rewrite_result(context, Shape::legacy(budget, offset)),
3222        span_start,
3223        span_end,
3224        false,
3225    );
3226    let item_vec = items.collect::<Vec<_>>();
3227    // FIXME: we don't need to collect here
3228    let tactic = definitive_tactic(&item_vec, ListTactic::Vertical, Separator::Comma, budget);
3229
3230    let mut comma_tactic = context.config.trailing_comma();
3231    // Kind of a hack because we don't usually have trailing commas in where-clauses.
3232    if comma_tactic == SeparatorTactic::Vertical || where_clause_option.suppress_comma {
3233        comma_tactic = SeparatorTactic::Never;
3234    }
3235
3236    let fmt = ListFormatting::new(Shape::legacy(budget, offset), context.config)
3237        .tactic(tactic)
3238        .trailing_separator(comma_tactic)
3239        .ends_with_newline(tactic.ends_with_newline(context.config.indent_style()))
3240        .preserve_newline(true);
3241    let preds_str = write_list(&item_vec, &fmt)?;
3242
3243    let end_length = if terminator == "{" {
3244        // If the brace is on the next line we don't need to count it otherwise it needs two
3245        // characters " {"
3246        match brace_style {
3247            BraceStyle::AlwaysNextLine | BraceStyle::SameLineWhere => 0,
3248            BraceStyle::PreferSameLine => 2,
3249        }
3250    } else if terminator == "=" {
3251        2
3252    } else {
3253        terminator.len()
3254    };
3255    if on_new_line
3256        || preds_str.contains('\n')
3257        || shape.indent.width() + " where ".len() + preds_str.len() + end_length > shape.width
3258    {
3259        Ok(format!(
3260            "\n{}where {}",
3261            (shape.indent + extra_indent).to_string(context.config),
3262            preds_str
3263        ))
3264    } else {
3265        Ok(format!(" where {preds_str}"))
3266    }
3267}
3268
3269fn missing_span_before_after_where(
3270    before_item_span_end: BytePos,
3271    predicates: &[ast::WherePredicate],
3272    where_span: Span,
3273) -> (Span, Span) {
3274    let missing_span_before = mk_sp(before_item_span_end, where_span.lo());
3275    // 5 = `where`
3276    let pos_after_where = where_span.lo() + BytePos(5);
3277    let missing_span_after = mk_sp(pos_after_where, predicates[0].span().lo());
3278    (missing_span_before, missing_span_after)
3279}
3280
3281fn rewrite_comments_before_after_where(
3282    context: &RewriteContext<'_>,
3283    span_before_where: Span,
3284    span_after_where: Span,
3285    shape: Shape,
3286) -> Result<(String, String), RewriteError> {
3287    let before_comment = rewrite_missing_comment(span_before_where, shape, context)?;
3288    let after_comment = rewrite_missing_comment(
3289        span_after_where,
3290        shape.block_indent(context.config.tab_spaces()),
3291        context,
3292    )?;
3293    Ok((before_comment, after_comment))
3294}
3295
3296fn format_header(
3297    context: &RewriteContext<'_>,
3298    item_name: &str,
3299    ident: symbol::Ident,
3300    vis: &ast::Visibility,
3301    offset: Indent,
3302) -> String {
3303    let mut result = String::with_capacity(128);
3304    let shape = Shape::indented(offset, context.config);
3305
3306    result.push_str(format_visibility(context, vis).trim());
3307
3308    // Check for a missing comment between the visibility and the item name.
3309    let after_vis = vis.span.hi();
3310    if let Some(before_item_name) = context
3311        .snippet_provider
3312        .opt_span_before(mk_sp(vis.span.lo(), ident.span.hi()), item_name.trim())
3313    {
3314        let missing_span = mk_sp(after_vis, before_item_name);
3315        if let Ok(result_with_comment) = combine_strs_with_missing_comments(
3316            context,
3317            &result,
3318            item_name,
3319            missing_span,
3320            shape,
3321            /* allow_extend */ true,
3322        ) {
3323            result = result_with_comment;
3324        }
3325    }
3326
3327    result.push_str(rewrite_ident(context, ident));
3328
3329    result
3330}
3331
3332#[derive(PartialEq, Eq, Clone, Copy)]
3333enum BracePos {
3334    None,
3335    Auto,
3336    ForceSameLine,
3337}
3338
3339fn format_generics(
3340    context: &RewriteContext<'_>,
3341    generics: &ast::Generics,
3342    brace_style: BraceStyle,
3343    brace_pos: BracePos,
3344    offset: Indent,
3345    span: Span,
3346    used_width: usize,
3347) -> Option<String> {
3348    let shape = Shape::legacy(context.budget(used_width + offset.width()), offset);
3349    let mut result = rewrite_generics(context, "", generics, shape).ok()?;
3350
3351    // If the generics are not parameterized then generics.span.hi() == 0,
3352    // so we use span.lo(), which is the position after `struct Foo`.
3353    let span_end_before_where = if !generics.params.is_empty() {
3354        generics.span.hi()
3355    } else {
3356        span.lo()
3357    };
3358    let (same_line_brace, missed_comments) = if !generics.where_clause.predicates.is_empty() {
3359        let budget = context.budget(last_line_used_width(&result, offset.width()));
3360        let mut option = WhereClauseOption::snuggled(&result);
3361        if brace_pos == BracePos::None {
3362            option.suppress_comma = true;
3363        }
3364        let where_clause_str = rewrite_where_clause(
3365            context,
3366            &generics.where_clause.predicates,
3367            generics.where_clause.span,
3368            brace_style,
3369            Shape::legacy(budget, offset.block_only()),
3370            true,
3371            "{",
3372            Some(span.hi()),
3373            span_end_before_where,
3374            option,
3375        )
3376        .ok()?;
3377        result.push_str(&where_clause_str);
3378        (
3379            brace_pos == BracePos::ForceSameLine || brace_style == BraceStyle::PreferSameLine,
3380            // missed comments are taken care of in #rewrite_where_clause
3381            None,
3382        )
3383    } else {
3384        (
3385            brace_pos == BracePos::ForceSameLine
3386                || (result.contains('\n') && brace_style == BraceStyle::PreferSameLine
3387                    || brace_style != BraceStyle::AlwaysNextLine)
3388                || trimmed_last_line_width(&result) == 1,
3389            rewrite_missing_comment(
3390                mk_sp(
3391                    span_end_before_where,
3392                    if brace_pos == BracePos::None {
3393                        span.hi()
3394                    } else {
3395                        context.snippet_provider.span_before_last(span, "{")
3396                    },
3397                ),
3398                shape,
3399                context,
3400            )
3401            .ok(),
3402        )
3403    };
3404    // add missing comments
3405    let missed_line_comments = missed_comments
3406        .filter(|missed_comments| !missed_comments.is_empty())
3407        .map_or(false, |missed_comments| {
3408            let is_block = is_last_comment_block(&missed_comments);
3409            let sep = if is_block { " " } else { "\n" };
3410            result.push_str(sep);
3411            result.push_str(&missed_comments);
3412            !is_block
3413        });
3414    if brace_pos == BracePos::None {
3415        return Some(result);
3416    }
3417    let total_used_width = last_line_used_width(&result, used_width);
3418    let remaining_budget = context.budget(total_used_width);
3419    // If the same line brace if forced, it indicates that we are rewriting an item with empty body,
3420    // and hence we take the closer into account as well for one line budget.
3421    // We assume that the closer has the same length as the opener.
3422    let overhead = if brace_pos == BracePos::ForceSameLine {
3423        // 3 = ` {}`
3424        3
3425    } else {
3426        // 2 = ` {`
3427        2
3428    };
3429    let forbid_same_line_brace = missed_line_comments || overhead > remaining_budget;
3430    if !forbid_same_line_brace && same_line_brace {
3431        result.push(' ');
3432    } else {
3433        result.push('\n');
3434        result.push_str(&offset.block_only().to_string(context.config));
3435    }
3436    result.push('{');
3437
3438    Some(result)
3439}
3440
3441impl Rewrite for ast::ForeignItem {
3442    fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
3443        self.rewrite_result(context, shape).ok()
3444    }
3445
3446    fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult {
3447        let attrs_str = self.attrs.rewrite_result(context, shape)?;
3448        // Drop semicolon or it will be interpreted as comment.
3449        // FIXME: this may be a faulty span from libsyntax.
3450        let span = mk_sp(self.span.lo(), self.span.hi() - BytePos(1));
3451
3452        let item_str = match self.kind {
3453            ast::ForeignItemKind::Fn(ref fn_kind) => {
3454                let ast::Fn {
3455                    defaultness,
3456                    ref sig,
3457                    ident,
3458                    ref generics,
3459                    ref body,
3460                    ..
3461                } = **fn_kind;
3462                if body.is_some() {
3463                    let mut visitor = FmtVisitor::from_context(context);
3464                    visitor.block_indent = shape.indent;
3465                    visitor.last_pos = self.span.lo();
3466                    let inner_attrs = inner_attributes(&self.attrs);
3467                    let fn_ctxt = visit::FnCtxt::Foreign;
3468                    visitor.visit_fn(
3469                        ident,
3470                        visit::FnKind::Fn(fn_ctxt, &self.vis, fn_kind),
3471                        &sig.decl,
3472                        self.span,
3473                        defaultness,
3474                        Some(&inner_attrs),
3475                    );
3476                    Ok(visitor.buffer.to_owned())
3477                } else {
3478                    rewrite_fn_base(
3479                        context,
3480                        shape.indent,
3481                        ident,
3482                        &FnSig::from_method_sig(sig, generics, &self.vis),
3483                        span,
3484                        FnBraceStyle::None,
3485                    )
3486                    .map(|(s, _, _)| format!("{};", s))
3487                }
3488            }
3489            ast::ForeignItemKind::Static(ref static_foreign_item) => {
3490                // FIXME(#21): we're dropping potential comments in between the
3491                // function kw here.
3492                let vis = format_visibility(context, &self.vis);
3493                let safety = format_safety(static_foreign_item.safety);
3494                let mut_str = format_mutability(static_foreign_item.mutability);
3495                let prefix = format!(
3496                    "{}{}static {}{}:",
3497                    vis,
3498                    safety,
3499                    mut_str,
3500                    rewrite_ident(context, static_foreign_item.ident)
3501                );
3502                // 1 = ;
3503                rewrite_assign_rhs(
3504                    context,
3505                    prefix,
3506                    &static_foreign_item.ty,
3507                    &RhsAssignKind::Ty,
3508                    shape
3509                        .sub_width(1)
3510                        .max_width_error(shape.width, static_foreign_item.ty.span)?,
3511                )
3512                .map(|s| s + ";")
3513            }
3514            ast::ForeignItemKind::TyAlias(ref ty_alias) => {
3515                let kind = ItemVisitorKind::ForeignItem;
3516                rewrite_type_alias(ty_alias, &self.vis, context, shape.indent, kind, self.span)
3517            }
3518            ast::ForeignItemKind::MacCall(ref mac) => {
3519                rewrite_macro(mac, context, shape, MacroPosition::Item)
3520            }
3521        }?;
3522
3523        let missing_span = if self.attrs.is_empty() {
3524            mk_sp(self.span.lo(), self.span.lo())
3525        } else {
3526            mk_sp(self.attrs[self.attrs.len() - 1].span.hi(), self.span.lo())
3527        };
3528        combine_strs_with_missing_comments(
3529            context,
3530            &attrs_str,
3531            &item_str,
3532            missing_span,
3533            shape,
3534            false,
3535        )
3536    }
3537}
3538
3539/// Rewrite the attributes of an item.
3540fn rewrite_attrs(
3541    context: &RewriteContext<'_>,
3542    item: &ast::Item,
3543    item_str: &str,
3544    shape: Shape,
3545) -> Option<String> {
3546    let attrs = filter_inline_attrs(&item.attrs, item.span());
3547    let attrs_str = attrs.rewrite(context, shape)?;
3548
3549    let missed_span = if attrs.is_empty() {
3550        mk_sp(item.span.lo(), item.span.lo())
3551    } else {
3552        mk_sp(attrs[attrs.len() - 1].span.hi(), item.span.lo())
3553    };
3554
3555    let allow_extend = if attrs.len() == 1 {
3556        let line_len = attrs_str.len() + 1 + item_str.len();
3557        !attrs.first().unwrap().is_doc_comment()
3558            && context.config.inline_attribute_width() >= line_len
3559    } else {
3560        false
3561    };
3562
3563    combine_strs_with_missing_comments(
3564        context,
3565        &attrs_str,
3566        item_str,
3567        missed_span,
3568        shape,
3569        allow_extend,
3570    )
3571    .ok()
3572}
3573
3574/// Rewrite an inline mod.
3575/// The given shape is used to format the mod's attributes.
3576pub(crate) fn rewrite_mod(
3577    context: &RewriteContext<'_>,
3578    item: &ast::Item,
3579    ident: Ident,
3580    attrs_shape: Shape,
3581) -> Option<String> {
3582    let mut result = String::with_capacity(32);
3583    result.push_str(&*format_visibility(context, &item.vis));
3584    result.push_str("mod ");
3585    result.push_str(rewrite_ident(context, ident));
3586    result.push(';');
3587    rewrite_attrs(context, item, &result, attrs_shape)
3588}
3589
3590/// Rewrite `extern crate foo;`.
3591/// The given shape is used to format the extern crate's attributes.
3592pub(crate) fn rewrite_extern_crate(
3593    context: &RewriteContext<'_>,
3594    item: &ast::Item,
3595    attrs_shape: Shape,
3596) -> Option<String> {
3597    assert!(is_extern_crate(item));
3598    let new_str = context.snippet(item.span);
3599    let item_str = if contains_comment(new_str) {
3600        new_str.to_owned()
3601    } else {
3602        let no_whitespace = &new_str.split_whitespace().collect::<Vec<&str>>().join(" ");
3603        String::from(&*Regex::new(r"\s;").unwrap().replace(no_whitespace, ";"))
3604    };
3605    rewrite_attrs(context, item, &item_str, attrs_shape)
3606}
3607
3608/// Returns `true` for `mod foo;`, false for `mod foo { .. }`.
3609pub(crate) fn is_mod_decl(item: &ast::Item) -> bool {
3610    !matches!(
3611        item.kind,
3612        ast::ItemKind::Mod(_, _, ast::ModKind::Loaded(_, ast::Inline::Yes, _, _))
3613    )
3614}
3615
3616pub(crate) fn is_use_item(item: &ast::Item) -> bool {
3617    matches!(item.kind, ast::ItemKind::Use(_))
3618}
3619
3620pub(crate) fn is_extern_crate(item: &ast::Item) -> bool {
3621    matches!(item.kind, ast::ItemKind::ExternCrate(..))
3622}