1 // Formatting top-level items - functions, structs, enums, traits, impls.
4 use std
::cmp
::{max, min, Ordering}
;
8 use rustc_ast
::{ast, ptr}
;
9 use rustc_span
::{symbol, BytePos, Span, DUMMY_SP}
;
11 use crate::attr
::filter_inline_attrs
;
13 combine_strs_with_missing_comments
, contains_comment
, is_last_comment_block
,
14 recover_comment_removed
, recover_missing_comment_in_span
, rewrite_missing_comment
,
17 use crate::config
::lists
::*;
18 use crate::config
::{BraceStyle, Config, IndentStyle, Version}
;
20 is_empty_block
, is_simple_block_stmt
, rewrite_assign_rhs
, rewrite_assign_rhs_with
,
21 rewrite_assign_rhs_with_comments
, RhsAssignKind
, RhsTactics
,
23 use crate::lists
::{definitive_tactic, itemize_list, write_list, ListFormatting, Separator}
;
24 use crate::macros
::{rewrite_macro, MacroPosition}
;
26 use crate::rewrite
::{Rewrite, RewriteContext}
;
27 use crate::shape
::{Indent, Shape}
;
28 use crate::source_map
::{LineRangeUtils, SpanUtils}
;
29 use crate::spanned
::Spanned
;
30 use crate::stmt
::Stmt
;
31 use crate::types
::opaque_ty
;
33 use crate::vertical
::rewrite_with_alignment
;
34 use crate::visitor
::FmtVisitor
;
36 const DEFAULT_VISIBILITY
: ast
::Visibility
= ast
::Visibility
{
37 kind
: ast
::VisibilityKind
::Inherited
,
42 fn type_annotation_separator(config
: &Config
) -> &str {
46 // Statements of the form
47 // let pat: ty = init;
48 impl Rewrite
for ast
::Local
{
49 fn rewrite(&self, context
: &RewriteContext
<'_
>, shape
: Shape
) -> Option
<String
> {
51 "Local::rewrite {:?} {} {:?}",
52 self, shape
.width
, shape
.indent
55 skip_out_of_file_lines_range
!(context
, self.span
);
57 if contains_skip(&self.attrs
) || matches
!(self.kind
, ast
::LocalKind
::InitElse(..)) {
61 let attrs_str
= self.attrs
.rewrite(context
, shape
)?
;
62 let mut result
= if attrs_str
.is_empty() {
65 combine_strs_with_missing_comments(
70 self.attrs
.last().map(|a
| a
.span
.hi()).unwrap(),
79 let pat_shape
= shape
.offset_left(4)?
;
81 let pat_shape
= pat_shape
.sub_width(1)?
;
82 let pat_str
= self.pat
.rewrite(context
, pat_shape
)?
;
83 result
.push_str(&pat_str
);
85 // String that is placed within the assignment pattern and expression.
87 let mut infix
= String
::with_capacity(32);
89 if let Some(ref ty
) = self.ty
{
90 let separator
= type_annotation_separator(context
.config
);
91 let ty_shape
= if pat_str
.contains('
\n'
) {
92 shape
.with_max_width(context
.config
)
96 .offset_left(last_line_width(&result
) + separator
.len())?
100 let rewrite
= ty
.rewrite(context
, ty_shape
)?
;
102 infix
.push_str(separator
);
103 infix
.push_str(&rewrite
);
106 if self.kind
.init().is_some() {
107 infix
.push_str(" =");
113 result
.push_str(&infix
);
115 if let Some((init
, _els
)) = self.kind
.init_else_opt() {
116 // 1 = trailing semicolon;
117 let nested_shape
= shape
.sub_width(1)?
;
119 result
= rewrite_assign_rhs(
123 &RhsAssignKind
::Expr(&init
.kind
, init
.span
),
134 // FIXME convert to using rewrite style rather than visitor
135 // FIXME format modules in this style
139 unsafety
: ast
::Unsafe
,
140 abi
: Cow
<'
static, str>,
141 vis
: Option
<&'a ast
::Visibility
>,
142 body
: Vec
<BodyElement
<'a
>>,
147 fn from_foreign_mod(fm
: &'a ast
::ForeignMod
, span
: Span
, config
: &Config
) -> Item
<'a
> {
149 unsafety
: fm
.unsafety
,
151 ast
::Extern
::from_abi(fm
.abi
),
152 config
.force_explicit_abi(),
159 .map(|i
| BodyElement
::ForeignItem(i
))
167 enum BodyElement
<'a
> {
168 // Stmt(&'a ast::Stmt),
169 // Field(&'a ast::ExprField),
170 // Variant(&'a ast::Variant),
171 // Item(&'a ast::Item),
172 ForeignItem(&'a ast
::ForeignItem
),
175 /// Represents a fn's signature.
176 pub(crate) struct FnSig
<'a
> {
177 decl
: &'a ast
::FnDecl
,
178 generics
: &'a ast
::Generics
,
180 is_async
: Cow
<'a
, ast
::Async
>,
181 constness
: ast
::Const
,
182 defaultness
: ast
::Defaultness
,
183 unsafety
: ast
::Unsafe
,
184 visibility
: &'a ast
::Visibility
,
188 pub(crate) fn from_method_sig(
189 method_sig
: &'a ast
::FnSig
,
190 generics
: &'a ast
::Generics
,
191 visibility
: &'a ast
::Visibility
,
194 unsafety
: method_sig
.header
.unsafety
,
195 is_async
: Cow
::Borrowed(&method_sig
.header
.asyncness
),
196 constness
: method_sig
.header
.constness
,
197 defaultness
: ast
::Defaultness
::Final
,
198 ext
: method_sig
.header
.ext
,
199 decl
: &*method_sig
.decl
,
205 pub(crate) fn from_fn_kind(
206 fn_kind
: &'a visit
::FnKind
<'_
>,
207 generics
: &'a ast
::Generics
,
208 decl
: &'a ast
::FnDecl
,
209 defaultness
: ast
::Defaultness
,
212 visit
::FnKind
::Fn(fn_ctxt
, _
, fn_sig
, vis
, _
) => match fn_ctxt
{
213 visit
::FnCtxt
::Assoc(..) => {
214 let mut fn_sig
= FnSig
::from_method_sig(fn_sig
, generics
, vis
);
215 fn_sig
.defaultness
= defaultness
;
221 ext
: fn_sig
.header
.ext
,
222 constness
: fn_sig
.header
.constness
,
223 is_async
: Cow
::Borrowed(&fn_sig
.header
.asyncness
),
225 unsafety
: fn_sig
.header
.unsafety
,
233 fn to_str(&self, context
: &RewriteContext
<'_
>) -> String
{
234 let mut result
= String
::with_capacity(128);
235 // Vis defaultness constness unsafety abi.
236 result
.push_str(&*format_visibility(context
, self.visibility
));
237 result
.push_str(format_defaultness(self.defaultness
));
238 result
.push_str(format_constness(self.constness
));
239 result
.push_str(format_async(&self.is_async
));
240 result
.push_str(format_unsafety(self.unsafety
));
241 result
.push_str(&format_extern(
243 context
.config
.force_explicit_abi(),
250 impl<'a
> FmtVisitor
<'a
> {
251 fn format_item(&mut self, item
: &Item
<'_
>) {
252 self.buffer
.push_str(format_unsafety(item
.unsafety
));
253 self.buffer
.push_str(&item
.abi
);
255 let snippet
= self.snippet(item
.span
);
256 let brace_pos
= snippet
.find_uncommented("{").unwrap();
259 if !item
.body
.is_empty() || contains_comment(&snippet
[brace_pos
..]) {
260 // FIXME: this skips comments between the extern keyword and the opening
262 self.last_pos
= item
.span
.lo() + BytePos(brace_pos
as u32 + 1);
263 self.block_indent
= self.block_indent
.block_indent(self.config
);
265 if !item
.body
.is_empty() {
266 for item
in &item
.body
{
267 self.format_body_element(item
);
271 self.format_missing_no_indent(item
.span
.hi() - BytePos(1));
272 self.block_indent
= self.block_indent
.block_unindent(self.config
);
273 let indent_str
= self.block_indent
.to_string(self.config
);
274 self.push_str(&indent_str
);
278 self.last_pos
= item
.span
.hi();
281 fn format_body_element(&mut self, element
: &BodyElement
<'_
>) {
283 BodyElement
::ForeignItem(item
) => self.format_foreign_item(item
),
287 pub(crate) fn format_foreign_mod(&mut self, fm
: &ast
::ForeignMod
, span
: Span
) {
288 let item
= Item
::from_foreign_mod(fm
, span
, self.config
);
289 self.format_item(&item
);
292 fn format_foreign_item(&mut self, item
: &ast
::ForeignItem
) {
293 let rewrite
= item
.rewrite(&self.get_context(), self.shape());
294 let hi
= item
.span
.hi();
295 let span
= if item
.attrs
.is_empty() {
298 mk_sp(item
.attrs
[0].span
.lo(), hi
)
300 self.push_rewrite(span
, rewrite
);
304 pub(crate) fn rewrite_fn_before_block(
307 ident
: symbol
::Ident
,
310 ) -> Option
<(String
, FnBraceStyle
)> {
311 let context
= self.get_context();
313 let mut fn_brace_style
= newline_for_brace(self.config
, &fn_sig
.generics
.where_clause
);
314 let (result
, _
, force_newline_brace
) =
315 rewrite_fn_base(&context
, indent
, ident
, fn_sig
, span
, fn_brace_style
)?
;
318 if self.config
.brace_style() == BraceStyle
::AlwaysNextLine
319 || force_newline_brace
320 || last_line_width(&result
) + 2 > self.shape().width
322 fn_brace_style
= FnBraceStyle
::NextLine
325 Some((result
, fn_brace_style
))
328 pub(crate) fn rewrite_required_fn(
331 ident
: symbol
::Ident
,
333 vis
: &ast
::Visibility
,
334 generics
: &ast
::Generics
,
336 ) -> Option
<String
> {
337 // Drop semicolon or it will be interpreted as comment.
338 let span
= mk_sp(span
.lo(), span
.hi() - BytePos(1));
339 let context
= self.get_context();
341 let (mut result
, ends_with_comment
, _
) = rewrite_fn_base(
345 &FnSig
::from_method_sig(sig
, generics
, vis
),
350 // If `result` ends with a comment, then remember to add a newline
351 if ends_with_comment
{
352 result
.push_str(&indent
.to_string_with_newline(context
.config
));
355 // Re-attach semicolon
361 pub(crate) fn single_line_fn(
365 inner_attrs
: Option
<&[ast
::Attribute
]>,
366 ) -> Option
<String
> {
367 if fn_str
.contains('
\n'
) || inner_attrs
.map_or(false, |a
| !a
.is_empty()) {
371 let context
= self.get_context();
373 if self.config
.empty_item_single_line()
374 && is_empty_block(&context
, block
, None
)
375 && self.block_indent
.width() + fn_str
.len() + 3 <= self.config
.max_width()
376 && !last_line_contains_single_line_comment(fn_str
)
378 return Some(format
!("{} {{}}", fn_str
));
381 if !self.config
.fn_single_line() || !is_simple_block_stmt(&context
, block
, None
) {
385 let res
= Stmt
::from_ast_node(block
.stmts
.first()?
, true)
386 .rewrite(&self.get_context(), self.shape())?
;
388 let width
= self.block_indent
.width() + fn_str
.len() + res
.len() + 5;
389 if !res
.contains('
\n'
) && width
<= self.config
.max_width() {
390 Some(format
!("{} {{ {} }}", fn_str
, res
))
396 pub(crate) fn visit_static(&mut self, static_parts
: &StaticParts
<'_
>) {
397 let rewrite
= rewrite_static(&self.get_context(), static_parts
, self.block_indent
);
398 self.push_rewrite(static_parts
.span
, rewrite
);
401 pub(crate) fn visit_struct(&mut self, struct_parts
: &StructParts
<'_
>) {
402 let is_tuple
= match struct_parts
.def
{
403 ast
::VariantData
::Tuple(..) => true,
406 let rewrite
= format_struct(&self.get_context(), struct_parts
, self.block_indent
, None
)
407 .map(|s
| if is_tuple { s + ";" }
else { s }
);
408 self.push_rewrite(struct_parts
.span
, rewrite
);
411 pub(crate) fn visit_enum(
413 ident
: symbol
::Ident
,
414 vis
: &ast
::Visibility
,
415 enum_def
: &ast
::EnumDef
,
416 generics
: &ast
::Generics
,
420 format_header(&self.get_context(), "enum ", ident
, vis
, self.block_indent
);
421 self.push_str(&enum_header
);
423 let enum_snippet
= self.snippet(span
);
424 let brace_pos
= enum_snippet
.find_uncommented("{").unwrap();
425 let body_start
= span
.lo() + BytePos(brace_pos
as u32 + 1);
426 let generics_str
= format_generics(
429 self.config
.brace_style(),
430 if enum_def
.variants
.is_empty() {
431 BracePos
::ForceSameLine
436 // make a span that starts right after `enum Foo`
437 mk_sp(ident
.span
.hi(), body_start
),
438 last_line_width(&enum_header
),
441 self.push_str(&generics_str
);
443 self.last_pos
= body_start
;
445 match self.format_variant_list(enum_def
, body_start
, span
.hi()) {
446 Some(ref s
) if enum_def
.variants
.is_empty() => self.push_str(s
),
448 self.push_rewrite(mk_sp(body_start
, span
.hi()), rw
);
449 self.block_indent
= self.block_indent
.block_unindent(self.config
);
454 // Format the body of an enum definition
455 fn format_variant_list(
457 enum_def
: &ast
::EnumDef
,
460 ) -> Option
<String
> {
461 if enum_def
.variants
.is_empty() {
462 let mut buffer
= String
::with_capacity(128);
464 let span
= mk_sp(body_lo
, body_hi
- BytePos(1));
465 format_empty_struct_or_tuple(
475 let mut result
= String
::with_capacity(1024);
476 let original_offset
= self.block_indent
;
477 self.block_indent
= self.block_indent
.block_indent(self.config
);
479 // If enum variants have discriminants, try to vertically align those,
480 // provided the discrims are not shifted too much to the right
481 let align_threshold
: usize = self.config
.enum_discrim_align_threshold();
482 let discr_ident_lens
: Vec
<usize> = enum_def
485 .filter(|var
| var
.disr_expr
.is_some())
486 .map(|var
| rewrite_ident(&self.get_context(), var
.ident
).len())
488 // cut the list at the point of longest discrim shorter than the threshold
489 // All of the discrims under the threshold will get padded, and all above - left as is.
490 let pad_discrim_ident_to
= *discr_ident_lens
492 .filter(|&l
| *l
<= align_threshold
)
496 let itemize_list_with
= |one_line_width
: usize| {
498 self.snippet_provider
,
499 enum_def
.variants
.iter(),
503 if !f
.attrs
.is_empty() {
510 |f
| self.format_variant(f
, one_line_width
, pad_discrim_ident_to
),
517 let mut items
: Vec
<_
> = itemize_list_with(self.config
.struct_variant_width());
519 // If one of the variants use multiple lines, use multi-lined formatting for all variants.
520 let has_multiline_variant
= items
.iter().any(|item
| item
.inner_as_ref().contains('
\n'
));
521 let has_single_line_variant
= items
.iter().any(|item
| !item
.inner_as_ref().contains('
\n'
));
522 if has_multiline_variant
&& has_single_line_variant
{
523 items
= itemize_list_with(0);
526 let shape
= self.shape().sub_width(2)?
;
527 let fmt
= ListFormatting
::new(shape
, self.config
)
528 .trailing_separator(self.config
.trailing_comma())
529 .preserve_newline(true);
531 let list
= write_list(&items
, &fmt
)?
;
532 result
.push_str(&list
);
533 result
.push_str(&original_offset
.to_string_with_newline(self.config
));
538 // Variant of an enum.
541 field
: &ast
::Variant
,
542 one_line_width
: usize,
543 pad_discrim_ident_to
: usize,
544 ) -> Option
<String
> {
545 if contains_skip(&field
.attrs
) {
546 let lo
= field
.attrs
[0].span
.lo();
547 let span
= mk_sp(lo
, field
.span
.hi());
548 return Some(self.snippet(span
).to_owned());
551 let context
= self.get_context();
553 let shape
= self.shape().sub_width(1)?
;
554 let attrs_str
= field
.attrs
.rewrite(&context
, shape
)?
;
558 .map_or(field
.span
.lo(), |attr
| attr
.span
.hi());
559 let span
= mk_sp(lo
, field
.span
.lo());
561 let variant_body
= match field
.data
{
562 ast
::VariantData
::Tuple(..) | ast
::VariantData
::Struct(..) => format_struct(
564 &StructParts
::from_variant(field
),
566 Some(one_line_width
),
568 ast
::VariantData
::Unit(..) => rewrite_ident(&context
, field
.ident
).to_owned(),
571 let variant_body
= if let Some(ref expr
) = field
.disr_expr
{
572 let lhs
= format
!("{:1$} =", variant_body
, pad_discrim_ident_to
);
573 let ex
= &*expr
.value
;
574 rewrite_assign_rhs_with(
579 &RhsAssignKind
::Expr(&ex
.kind
, ex
.span
),
580 RhsTactics
::AllowOverflow
,
586 combine_strs_with_missing_comments(&context
, &attrs_str
, &variant_body
, span
, shape
, false)
589 fn visit_impl_items(&mut self, items
: &[ptr
::P
<ast
::AssocItem
>]) {
590 if self.get_context().config
.reorder_impl_items() {
591 type TyOpt
= Option
<ptr
::P
<ast
::Ty
>>;
592 use crate::ast
::AssocItemKind
::*;
593 let is_type
= |ty
: &TyOpt
| opaque_ty(ty
).is_none();
594 let is_opaque
= |ty
: &TyOpt
| opaque_ty(ty
).is_some();
595 let both_type
= |l
: &TyOpt
, r
: &TyOpt
| is_type(l
) && is_type(r
);
596 let both_opaque
= |l
: &TyOpt
, r
: &TyOpt
| is_opaque(l
) && is_opaque(r
);
597 let need_empty_line
= |a
: &ast
::AssocItemKind
, b
: &ast
::AssocItemKind
| match (a
, b
) {
598 (TyAlias(lty
), TyAlias(rty
))
599 if both_type(<y
.ty
, &rty
.ty
) || both_opaque(<y
.ty
, &rty
.ty
) =>
603 (Const(..), Const(..)) => false,
607 // Create visitor for each items, then reorder them.
608 let mut buffer
= vec
![];
610 self.visit_impl_item(item
);
611 buffer
.push((self.buffer
.clone(), item
.clone()));
615 buffer
.sort_by(|(_
, a
), (_
, b
)| match (&a
.kind
, &b
.kind
) {
616 (TyAlias(lty
), TyAlias(rty
))
617 if both_type(<y
.ty
, &rty
.ty
) || both_opaque(<y
.ty
, &rty
.ty
) =>
619 a
.ident
.as_str().cmp(b
.ident
.as_str())
621 (Const(..), Const(..)) | (MacCall(..), MacCall(..)) => {
622 a
.ident
.as_str().cmp(b
.ident
.as_str())
624 (Fn(..), Fn(..)) => a
.span
.lo().cmp(&b
.span
.lo()),
625 (TyAlias(ty
), _
) if is_type(&ty
.ty
) => Ordering
::Less
,
626 (_
, TyAlias(ty
)) if is_type(&ty
.ty
) => Ordering
::Greater
,
627 (TyAlias(..), _
) => Ordering
::Less
,
628 (_
, TyAlias(..)) => Ordering
::Greater
,
629 (Const(..), _
) => Ordering
::Less
,
630 (_
, Const(..)) => Ordering
::Greater
,
631 (MacCall(..), _
) => Ordering
::Less
,
632 (_
, MacCall(..)) => Ordering
::Greater
,
634 let mut prev_kind
= None
;
635 for (buf
, item
) in buffer
{
636 // Make sure that there are at least a single empty line between
637 // different impl items.
640 .map_or(false, |prev_kind
| need_empty_line(prev_kind
, &item
.kind
))
644 let indent_str
= self.block_indent
.to_string_with_newline(self.config
);
645 self.push_str(&indent_str
);
646 self.push_str(buf
.trim());
647 prev_kind
= Some(item
.kind
.clone());
651 self.visit_impl_item(item
);
657 pub(crate) fn format_impl(
658 context
: &RewriteContext
<'_
>,
662 ) -> Option
<String
> {
669 let mut result
= String
::with_capacity(128);
670 let ref_and_type
= format_impl_ref_and_type(context
, item
, iimpl
, offset
)?
;
671 let sep
= offset
.to_string_with_newline(context
.config
);
672 result
.push_str(&ref_and_type
);
674 let where_budget
= if result
.contains('
\n'
) {
675 context
.config
.max_width()
677 context
.budget(last_line_width(&result
))
680 let mut option
= WhereClauseOption
::snuggled(&ref_and_type
);
681 let snippet
= context
.snippet(item
.span
);
682 let open_pos
= snippet
.find_uncommented("{")?
+ 1;
683 if !contains_comment(&snippet
[open_pos
..])
685 && generics
.where_clause
.predicates
.len() == 1
686 && !result
.contains('
\n'
)
688 option
.suppress_comma();
690 option
.allow_single_line();
693 let missing_span
= mk_sp(self_ty
.span
.hi(), item
.span
.hi());
694 let where_span_end
= context
.snippet_provider
.opt_span_before(missing_span
, "{");
695 let where_clause_str
= rewrite_where_clause(
697 &generics
.where_clause
.predicates
,
698 generics
.where_clause
.span
,
699 context
.config
.brace_style(),
700 Shape
::legacy(where_budget
, offset
.block_only()),
708 // If there is no where-clause, we may have missing comments between the trait name and
709 // the opening brace.
710 if generics
.where_clause
.predicates
.is_empty() {
711 if let Some(hi
) = where_span_end
{
712 match recover_missing_comment_in_span(
713 mk_sp(self_ty
.span
.hi(), hi
),
714 Shape
::indented(offset
, context
.config
),
716 last_line_width(&result
),
718 Some(ref missing_comment
) if !missing_comment
.is_empty() => {
719 result
.push_str(missing_comment
);
726 if is_impl_single_line(context
, items
.as_slice(), &result
, &where_clause_str
, item
)?
{
727 result
.push_str(&where_clause_str
);
728 if where_clause_str
.contains('
\n'
) || last_line_contains_single_line_comment(&result
) {
729 // if the where_clause contains extra comments AND
730 // there is only one where-clause predicate
731 // recover the suppressed comma in single line where_clause formatting
732 if generics
.where_clause
.predicates
.len() == 1 {
735 result
.push_str(&format
!("{}{{{}}}", sep
, sep
));
737 result
.push_str(" {}");
742 result
.push_str(&where_clause_str
);
744 let need_newline
= last_line_contains_single_line_comment(&result
) || result
.contains('
\n'
);
745 match context
.config
.brace_style() {
746 _
if need_newline
=> result
.push_str(&sep
),
747 BraceStyle
::AlwaysNextLine
=> result
.push_str(&sep
),
748 BraceStyle
::PreferSameLine
=> result
.push(' '
),
749 BraceStyle
::SameLineWhere
=> {
750 if !where_clause_str
.is_empty() {
751 result
.push_str(&sep
);
759 // this is an impl body snippet(impl SampleImpl { /* here */ })
760 let lo
= max(self_ty
.span
.hi(), generics
.where_clause
.span
.hi());
761 let snippet
= context
.snippet(mk_sp(lo
, item
.span
.hi()));
762 let open_pos
= snippet
.find_uncommented("{")?
+ 1;
764 if !items
.is_empty() || contains_comment(&snippet
[open_pos
..]) {
765 let mut visitor
= FmtVisitor
::from_context(context
);
766 let item_indent
= offset
.block_only().block_indent(context
.config
);
767 visitor
.block_indent
= item_indent
;
768 visitor
.last_pos
= lo
+ BytePos(open_pos
as u32);
770 visitor
.visit_attrs(&item
.attrs
, ast
::AttrStyle
::Inner
);
771 visitor
.visit_impl_items(items
);
773 visitor
.format_missing(item
.span
.hi() - BytePos(1));
775 let inner_indent_str
= visitor
.block_indent
.to_string_with_newline(context
.config
);
776 let outer_indent_str
= offset
.block_only().to_string_with_newline(context
.config
);
778 result
.push_str(&inner_indent_str
);
779 result
.push_str(visitor
.buffer
.trim());
780 result
.push_str(&outer_indent_str
);
781 } else if need_newline
|| !context
.config
.empty_item_single_line() {
782 result
.push_str(&sep
);
790 fn is_impl_single_line(
791 context
: &RewriteContext
<'_
>,
792 items
: &[ptr
::P
<ast
::AssocItem
>],
794 where_clause_str
: &str,
797 let snippet
= context
.snippet(item
.span
);
798 let open_pos
= snippet
.find_uncommented("{")?
+ 1;
801 context
.config
.empty_item_single_line()
803 && !result
.contains('
\n'
)
804 && result
.len() + where_clause_str
.len() <= context
.config
.max_width()
805 && !contains_comment(&snippet
[open_pos
..]),
809 fn format_impl_ref_and_type(
810 context
: &RewriteContext
<'_
>,
814 ) -> Option
<String
> {
821 of_trait
: ref trait_ref
,
825 let mut result
= String
::with_capacity(128);
827 result
.push_str(&format_visibility(context
, &item
.vis
));
828 result
.push_str(format_defaultness(defaultness
));
829 result
.push_str(format_unsafety(unsafety
));
831 let shape
= if context
.config
.version() == Version
::Two
{
832 Shape
::indented(offset
+ last_line_width(&result
), context
.config
)
834 generics_shape_from_config(
836 Shape
::indented(offset
+ last_line_width(&result
), context
.config
),
840 let generics_str
= rewrite_generics(context
, "impl", generics
, shape
)?
;
841 result
.push_str(&generics_str
);
842 result
.push_str(format_constness_right(constness
));
844 let polarity_str
= match polarity
{
845 ast
::ImplPolarity
::Negative(_
) => "!",
846 ast
::ImplPolarity
::Positive
=> "",
849 let polarity_overhead
;
850 let trait_ref_overhead
;
851 if let Some(ref trait_ref
) = *trait_ref
{
852 let result_len
= last_line_width(&result
);
853 result
.push_str(&rewrite_trait_ref(
860 polarity_overhead
= 0; // already written
861 trait_ref_overhead
= " for".len();
863 polarity_overhead
= polarity_str
.len();
864 trait_ref_overhead
= 0;
867 // Try to put the self type in a single line.
868 let curly_brace_overhead
= if generics
.where_clause
.predicates
.is_empty() {
869 // If there is no where-clause adapt budget for type formatting to take space and curly
870 // brace into account.
871 match context
.config
.brace_style() {
872 BraceStyle
::AlwaysNextLine
=> 0,
879 last_line_width(&result
) + polarity_overhead
+ trait_ref_overhead
+ curly_brace_overhead
;
880 // 1 = space before the type.
881 let budget
= context
.budget(used_space
+ 1);
882 if let Some(self_ty_str
) = self_ty
.rewrite(context
, Shape
::legacy(budget
, offset
)) {
883 if !self_ty_str
.contains('
\n'
) {
884 if trait_ref
.is_some() {
885 result
.push_str(" for ");
888 result
.push_str(polarity_str
);
890 result
.push_str(&self_ty_str
);
895 // Couldn't fit the self type on a single line, put it on a new line.
897 // Add indentation of one additional tab.
898 let new_line_offset
= offset
.block_indent(context
.config
);
899 result
.push_str(&new_line_offset
.to_string(context
.config
));
900 if trait_ref
.is_some() {
901 result
.push_str("for ");
903 result
.push_str(polarity_str
);
905 let budget
= context
.budget(last_line_width(&result
) + polarity_overhead
);
906 let type_offset
= match context
.config
.indent_style() {
907 IndentStyle
::Visual
=> new_line_offset
+ trait_ref_overhead
,
908 IndentStyle
::Block
=> new_line_offset
,
910 result
.push_str(&*self_ty
.rewrite(context
, Shape
::legacy(budget
, type_offset
))?
);
914 fn rewrite_trait_ref(
915 context
: &RewriteContext
<'_
>,
916 trait_ref
: &ast
::TraitRef
,
920 ) -> Option
<String
> {
921 // 1 = space between generics and trait_ref
922 let used_space
= 1 + polarity_str
.len() + result_len
;
923 let shape
= Shape
::indented(offset
+ used_space
, context
.config
);
924 if let Some(trait_ref_str
) = trait_ref
.rewrite(context
, shape
) {
925 if !trait_ref_str
.contains('
\n'
) {
926 return Some(format
!(" {}{}", polarity_str
, trait_ref_str
));
929 // We could not make enough space for trait_ref, so put it on new line.
930 let offset
= offset
.block_indent(context
.config
);
931 let shape
= Shape
::indented(offset
, context
.config
);
932 let trait_ref_str
= trait_ref
.rewrite(context
, shape
)?
;
935 offset
.to_string_with_newline(context
.config
),
941 pub(crate) struct StructParts
<'a
> {
943 ident
: symbol
::Ident
,
944 vis
: &'a ast
::Visibility
,
945 def
: &'a ast
::VariantData
,
946 generics
: Option
<&'a ast
::Generics
>,
950 impl<'a
> StructParts
<'a
> {
951 fn format_header(&self, context
: &RewriteContext
<'_
>, offset
: Indent
) -> String
{
952 format_header(context
, self.prefix
, self.ident
, self.vis
, offset
)
955 fn from_variant(variant
: &'a ast
::Variant
) -> Self {
958 ident
: variant
.ident
,
959 vis
: &DEFAULT_VISIBILITY
,
966 pub(crate) fn from_item(item
: &'a ast
::Item
) -> Self {
967 let (prefix
, def
, generics
) = match item
.kind
{
968 ast
::ItemKind
::Struct(ref def
, ref generics
) => ("struct ", def
, generics
),
969 ast
::ItemKind
::Union(ref def
, ref generics
) => ("union ", def
, generics
),
977 generics
: Some(generics
),
984 context
: &RewriteContext
<'_
>,
985 struct_parts
: &StructParts
<'_
>,
987 one_line_width
: Option
<usize>,
988 ) -> Option
<String
> {
989 match *struct_parts
.def
{
990 ast
::VariantData
::Unit(..) => format_unit_struct(context
, struct_parts
, offset
),
991 ast
::VariantData
::Tuple(ref fields
, _
) => {
992 format_tuple_struct(context
, struct_parts
, fields
, offset
)
994 ast
::VariantData
::Struct(ref fields
, _
) => {
995 format_struct_struct(context
, struct_parts
, fields
, offset
, one_line_width
)
1000 pub(crate) fn format_trait(
1001 context
: &RewriteContext
<'_
>,
1004 ) -> Option
<String
> {
1005 if let ast
::ItemKind
::Trait(trait_kind
) = &item
.kind
{
1013 let mut result
= String
::with_capacity(128);
1014 let header
= format
!(
1016 format_visibility(context
, &item
.vis
),
1017 format_unsafety(unsafety
),
1018 format_auto(is_auto
),
1020 result
.push_str(&header
);
1022 let body_lo
= context
.snippet_provider
.span_after(item
.span
, "{");
1024 let shape
= Shape
::indented(offset
, context
.config
).offset_left(result
.len())?
;
1026 rewrite_generics(context
, rewrite_ident(context
, item
.ident
), generics
, shape
)?
;
1027 result
.push_str(&generics_str
);
1029 // FIXME(#2055): rustfmt fails to format when there are comments between trait bounds.
1030 if !bounds
.is_empty() {
1031 let ident_hi
= context
1033 .span_after(item
.span
, item
.ident
.as_str());
1034 let bound_hi
= bounds
.last().unwrap().span().hi();
1035 let snippet
= context
.snippet(mk_sp(ident_hi
, bound_hi
));
1036 if contains_comment(snippet
) {
1040 result
= rewrite_assign_rhs_with(
1045 &RhsAssignKind
::Bounds
,
1046 RhsTactics
::ForceNextLineWithoutIndent
,
1050 // Rewrite where-clause.
1051 if !generics
.where_clause
.predicates
.is_empty() {
1052 let where_on_new_line
= context
.config
.indent_style() != IndentStyle
::Block
;
1054 let where_budget
= context
.budget(last_line_width(&result
));
1055 let pos_before_where
= if bounds
.is_empty() {
1056 generics
.where_clause
.span
.lo()
1058 bounds
[bounds
.len() - 1].span().hi()
1060 let option
= WhereClauseOption
::snuggled(&generics_str
);
1061 let where_clause_str
= rewrite_where_clause(
1063 &generics
.where_clause
.predicates
,
1064 generics
.where_clause
.span
,
1065 context
.config
.brace_style(),
1066 Shape
::legacy(where_budget
, offset
.block_only()),
1073 // If the where-clause cannot fit on the same line,
1074 // put the where-clause on a new line
1075 if !where_clause_str
.contains('
\n'
)
1076 && last_line_width(&result
) + where_clause_str
.len() + offset
.width()
1077 > context
.config
.comment_width()
1079 let width
= offset
.block_indent
+ context
.config
.tab_spaces() - 1;
1080 let where_indent
= Indent
::new(0, width
);
1081 result
.push_str(&where_indent
.to_string_with_newline(context
.config
));
1083 result
.push_str(&where_clause_str
);
1085 let item_snippet
= context
.snippet(item
.span
);
1086 if let Some(lo
) = item_snippet
.find('
/'
) {
1088 let comment_hi
= body_lo
- BytePos(1);
1089 let comment_lo
= item
.span
.lo() + BytePos(lo
as u32);
1090 if comment_lo
< comment_hi
{
1091 match recover_missing_comment_in_span(
1092 mk_sp(comment_lo
, comment_hi
),
1093 Shape
::indented(offset
, context
.config
),
1095 last_line_width(&result
),
1097 Some(ref missing_comment
) if !missing_comment
.is_empty() => {
1098 result
.push_str(missing_comment
);
1106 let block_span
= mk_sp(generics
.where_clause
.span
.hi(), item
.span
.hi());
1107 let snippet
= context
.snippet(block_span
);
1108 let open_pos
= snippet
.find_uncommented("{")?
+ 1;
1110 match context
.config
.brace_style() {
1111 _
if last_line_contains_single_line_comment(&result
)
1112 || last_line_width(&result
) + 2 > context
.budget(offset
.width()) =>
1114 result
.push_str(&offset
.to_string_with_newline(context
.config
));
1116 _
if context
.config
.empty_item_single_line()
1118 && !result
.contains('
\n'
)
1119 && !contains_comment(&snippet
[open_pos
..]) =>
1121 result
.push_str(" {}");
1122 return Some(result
);
1124 BraceStyle
::AlwaysNextLine
=> {
1125 result
.push_str(&offset
.to_string_with_newline(context
.config
));
1127 BraceStyle
::PreferSameLine
=> result
.push(' '
),
1128 BraceStyle
::SameLineWhere
=> {
1129 if result
.contains('
\n'
)
1130 || (!generics
.where_clause
.predicates
.is_empty() && !items
.is_empty())
1132 result
.push_str(&offset
.to_string_with_newline(context
.config
));
1140 let outer_indent_str
= offset
.block_only().to_string_with_newline(context
.config
);
1142 if !items
.is_empty() || contains_comment(&snippet
[open_pos
..]) {
1143 let mut visitor
= FmtVisitor
::from_context(context
);
1144 visitor
.block_indent
= offset
.block_only().block_indent(context
.config
);
1145 visitor
.last_pos
= block_span
.lo() + BytePos(open_pos
as u32);
1148 visitor
.visit_trait_item(item
);
1151 visitor
.format_missing(item
.span
.hi() - BytePos(1));
1153 let inner_indent_str
= visitor
.block_indent
.to_string_with_newline(context
.config
);
1155 result
.push_str(&inner_indent_str
);
1156 result
.push_str(visitor
.buffer
.trim());
1157 result
.push_str(&outer_indent_str
);
1158 } else if result
.contains('
\n'
) {
1159 result
.push_str(&outer_indent_str
);
1169 pub(crate) struct TraitAliasBounds
<'a
> {
1170 generic_bounds
: &'a ast
::GenericBounds
,
1171 generics
: &'a ast
::Generics
,
1174 impl<'a
> Rewrite
for TraitAliasBounds
<'a
> {
1175 fn rewrite(&self, context
: &RewriteContext
<'_
>, shape
: Shape
) -> Option
<String
> {
1176 let generic_bounds_str
= self.generic_bounds
.rewrite(context
, shape
)?
;
1178 let mut option
= WhereClauseOption
::new(true, WhereClauseSpace
::None
);
1179 option
.allow_single_line();
1181 let where_str
= rewrite_where_clause(
1183 &self.generics
.where_clause
.predicates
,
1184 self.generics
.where_clause
.span
,
1185 context
.config
.brace_style(),
1190 self.generics
.where_clause
.span
.lo(),
1194 let fits_single_line
= !generic_bounds_str
.contains('
\n'
)
1195 && !where_str
.contains('
\n'
)
1196 && generic_bounds_str
.len() + where_str
.len() < shape
.width
;
1197 let space
= if generic_bounds_str
.is_empty() || where_str
.is_empty() {
1199 } else if fits_single_line
{
1202 shape
.indent
.to_string_with_newline(context
.config
)
1205 Some(format
!("{}{}{}", generic_bounds_str
, space
, where_str
))
1209 pub(crate) fn format_trait_alias(
1210 context
: &RewriteContext
<'_
>,
1211 ident
: symbol
::Ident
,
1212 vis
: &ast
::Visibility
,
1213 generics
: &ast
::Generics
,
1214 generic_bounds
: &ast
::GenericBounds
,
1216 ) -> Option
<String
> {
1217 let alias
= rewrite_ident(context
, ident
);
1218 // 6 = "trait ", 2 = " ="
1219 let g_shape
= shape
.offset_left(6)?
.sub_width(2)?
;
1220 let generics_str
= rewrite_generics(context
, alias
, generics
, g_shape
)?
;
1221 let vis_str
= format_visibility(context
, vis
);
1222 let lhs
= format
!("{}trait {} =", vis_str
, generics_str
);
1224 let trait_alias_bounds
= TraitAliasBounds
{
1231 &trait_alias_bounds
,
1232 &RhsAssignKind
::Bounds
,
1233 shape
.sub_width(1)?
,
1238 fn format_unit_struct(
1239 context
: &RewriteContext
<'_
>,
1240 p
: &StructParts
<'_
>,
1242 ) -> Option
<String
> {
1243 let header_str
= format_header(context
, p
.prefix
, p
.ident
, p
.vis
, offset
);
1244 let generics_str
= if let Some(generics
) = p
.generics
{
1245 let hi
= context
.snippet_provider
.span_before(p
.span
, ";");
1249 context
.config
.brace_style(),
1252 // make a span that starts right after `struct Foo`
1253 mk_sp(p
.ident
.span
.hi(), hi
),
1254 last_line_width(&header_str
),
1259 Some(format
!("{}{};", header_str
, generics_str
))
1262 pub(crate) fn format_struct_struct(
1263 context
: &RewriteContext
<'_
>,
1264 struct_parts
: &StructParts
<'_
>,
1265 fields
: &[ast
::FieldDef
],
1267 one_line_width
: Option
<usize>,
1268 ) -> Option
<String
> {
1269 let mut result
= String
::with_capacity(1024);
1270 let span
= struct_parts
.span
;
1272 let header_str
= struct_parts
.format_header(context
, offset
);
1273 result
.push_str(&header_str
);
1275 let header_hi
= struct_parts
.ident
.span
.hi();
1276 let body_lo
= if let Some(generics
) = struct_parts
.generics
{
1277 // Adjust the span to start at the end of the generic arguments before searching for the '{'
1278 let span
= span
.with_lo(generics
.span
.hi());
1279 context
.snippet_provider
.span_after(span
, "{")
1281 context
.snippet_provider
.span_after(span
, "{")
1284 let generics_str
= match struct_parts
.generics
{
1285 Some(g
) => format_generics(
1288 context
.config
.brace_style(),
1289 if fields
.is_empty() {
1290 BracePos
::ForceSameLine
1295 // make a span that starts right after `struct Foo`
1296 mk_sp(header_hi
, body_lo
),
1297 last_line_width(&result
),
1300 // 3 = ` {}`, 2 = ` {`.
1301 let overhead
= if fields
.is_empty() { 3 }
else { 2 }
;
1302 if (context
.config
.brace_style() == BraceStyle
::AlwaysNextLine
&& !fields
.is_empty())
1303 || context
.config
.max_width() < overhead
+ result
.len()
1305 format
!("\n{}{{", offset
.block_only().to_string(context
.config
))
1312 let overhead
= if fields
.is_empty() { 1 }
else { 0 }
;
1313 let total_width
= result
.len() + generics_str
.len() + overhead
;
1314 if !generics_str
.is_empty()
1315 && !generics_str
.contains('
\n'
)
1316 && total_width
> context
.config
.max_width()
1319 result
.push_str(&offset
.to_string(context
.config
));
1320 result
.push_str(generics_str
.trim_start());
1322 result
.push_str(&generics_str
);
1325 if fields
.is_empty() {
1326 let inner_span
= mk_sp(body_lo
, span
.hi() - BytePos(1));
1327 format_empty_struct_or_tuple(context
, inner_span
, offset
, &mut result
, "", "}");
1328 return Some(result
);
1332 let one_line_budget
= context
.budget(result
.len() + 3 + offset
.width());
1333 let one_line_budget
=
1334 one_line_width
.map_or(0, |one_line_width
| min(one_line_width
, one_line_budget
));
1336 let items_str
= rewrite_with_alignment(
1339 Shape
::indented(offset
.block_indent(context
.config
), context
.config
).sub_width(1)?
,
1340 mk_sp(body_lo
, span
.hi()),
1344 if !items_str
.contains('
\n'
)
1345 && !result
.contains('
\n'
)
1346 && items_str
.len() <= one_line_budget
1347 && !last_line_contains_single_line_comment(&items_str
)
1349 Some(format
!("{} {} }}", result
, items_str
))
1355 .block_indent(context
.config
)
1356 .to_string(context
.config
),
1358 offset
.to_string(context
.config
)
1363 fn get_bytepos_after_visibility(vis
: &ast
::Visibility
, default_span
: Span
) -> BytePos
{
1365 ast
::VisibilityKind
::Crate(..) | ast
::VisibilityKind
::Restricted { .. }
=> vis
.span
.hi(),
1366 _
=> default_span
.lo(),
1370 // Format tuple or struct without any fields. We need to make sure that the comments
1371 // inside the delimiters are preserved.
1372 fn format_empty_struct_or_tuple(
1373 context
: &RewriteContext
<'_
>,
1376 result
: &mut String
,
1380 // 3 = " {}" or "();"
1381 let used_width
= last_line_used_width(result
, offset
.width()) + 3;
1382 if used_width
> context
.config
.max_width() {
1383 result
.push_str(&offset
.to_string_with_newline(context
.config
))
1385 result
.push_str(opener
);
1387 // indented shape for proper indenting of multi-line comments
1388 let shape
= Shape
::indented(offset
.block_indent(context
.config
), context
.config
);
1389 match rewrite_missing_comment(span
, shape
, context
) {
1390 Some(ref s
) if s
.is_empty() => (),
1392 let is_multi_line
= !is_single_line(s
);
1393 if is_multi_line
|| first_line_contains_single_line_comment(s
) {
1394 let nested_indent_str
= offset
1395 .block_indent(context
.config
)
1396 .to_string_with_newline(context
.config
);
1397 result
.push_str(&nested_indent_str
);
1400 if is_multi_line
|| last_line_contains_single_line_comment(s
) {
1401 result
.push_str(&offset
.to_string_with_newline(context
.config
));
1404 None
=> result
.push_str(context
.snippet(span
)),
1406 result
.push_str(closer
);
1409 fn format_tuple_struct(
1410 context
: &RewriteContext
<'_
>,
1411 struct_parts
: &StructParts
<'_
>,
1412 fields
: &[ast
::FieldDef
],
1414 ) -> Option
<String
> {
1415 let mut result
= String
::with_capacity(1024);
1416 let span
= struct_parts
.span
;
1418 let header_str
= struct_parts
.format_header(context
, offset
);
1419 result
.push_str(&header_str
);
1421 let body_lo
= if fields
.is_empty() {
1422 let lo
= get_bytepos_after_visibility(struct_parts
.vis
, span
);
1425 .span_after(mk_sp(lo
, span
.hi()), "(")
1429 let body_hi
= if fields
.is_empty() {
1432 .span_after(mk_sp(body_lo
, span
.hi()), ")")
1434 // This is a dirty hack to work around a missing `)` from the span of the last field.
1435 let last_arg_span
= fields
[fields
.len() - 1].span
;
1438 .opt_span_after(mk_sp(last_arg_span
.hi(), span
.hi()), ")")
1439 .unwrap_or_else(|| last_arg_span
.hi())
1442 let where_clause_str
= match struct_parts
.generics
{
1444 let budget
= context
.budget(last_line_width(&header_str
));
1445 let shape
= Shape
::legacy(budget
, offset
);
1446 let generics_str
= rewrite_generics(context
, "", generics
, shape
)?
;
1447 result
.push_str(&generics_str
);
1449 let where_budget
= context
.budget(last_line_width(&result
));
1450 let option
= WhereClauseOption
::new(true, WhereClauseSpace
::Newline
);
1451 rewrite_where_clause(
1453 &generics
.where_clause
.predicates
,
1454 generics
.where_clause
.span
,
1455 context
.config
.brace_style(),
1456 Shape
::legacy(where_budget
, offset
.block_only()),
1464 None
=> "".to_owned(),
1467 if fields
.is_empty() {
1468 let body_hi
= context
1470 .span_before(mk_sp(body_lo
, span
.hi()), ")");
1471 let inner_span
= mk_sp(body_lo
, body_hi
);
1472 format_empty_struct_or_tuple(context
, inner_span
, offset
, &mut result
, "(", ")");
1474 let shape
= Shape
::indented(offset
, context
.config
).sub_width(1)?
;
1475 let lo
= if let Some(generics
) = struct_parts
.generics
{
1478 struct_parts
.ident
.span
.hi()
1480 result
= overflow
::rewrite_with_parens(
1485 mk_sp(lo
, span
.hi()),
1486 context
.config
.fn_call_width(),
1491 if !where_clause_str
.is_empty()
1492 && !where_clause_str
.contains('
\n'
)
1493 && (result
.contains('
\n'
)
1494 || offset
.block_indent
+ result
.len() + where_clause_str
.len() + 1
1495 > context
.config
.max_width())
1497 // We need to put the where-clause on a new line, but we didn't
1498 // know that earlier, so the where-clause will not be indented properly.
1501 &(offset
.block_only() + (context
.config
.tab_spaces() - 1)).to_string(context
.config
),
1504 result
.push_str(&where_clause_str
);
1509 pub(crate) enum ItemVisitorKind
<'a
> {
1510 Item(&'a ast
::Item
),
1511 AssocTraitItem(&'a ast
::AssocItem
),
1512 AssocImplItem(&'a ast
::AssocItem
),
1513 ForeignItem(&'a ast
::ForeignItem
),
1516 struct TyAliasRewriteInfo
<'c
, 'g
>(
1517 &'c RewriteContext
<'c
>,
1520 (ast
::TyAliasWhereClause
, ast
::TyAliasWhereClause
),
1526 pub(crate) fn rewrite_type_alias
<'a
, 'b
>(
1527 ty_alias_kind
: &ast
::TyAlias
,
1528 context
: &RewriteContext
<'a
>,
1530 visitor_kind
: &ItemVisitorKind
<'b
>,
1532 ) -> Option
<String
> {
1533 use ItemVisitorKind
::*;
1541 where_predicates_split
,
1543 let ty_opt
= ty
.as_ref();
1544 let (ident
, vis
) = match visitor_kind
{
1545 Item(i
) => (i
.ident
, &i
.vis
),
1546 AssocTraitItem(i
) | AssocImplItem(i
) => (i
.ident
, &i
.vis
),
1547 ForeignItem(i
) => (i
.ident
, &i
.vis
),
1549 let rw_info
= &TyAliasRewriteInfo(
1554 where_predicates_split
,
1558 let op_ty
= opaque_ty(ty
);
1559 // Type Aliases are formatted slightly differently depending on the context
1560 // in which they appear, whether they are opaque, and whether they are associated.
1561 // https://rustc-dev-guide.rust-lang.org/opaque-types-type-alias-impl-trait.html
1562 // https://github.com/rust-dev-tools/fmt-rfcs/blob/master/guide/items.md#type-aliases
1563 match (visitor_kind
, &op_ty
) {
1564 (Item(_
) | AssocTraitItem(_
) | ForeignItem(_
), Some(op_bounds
)) => {
1565 let op
= OpaqueType { bounds: op_bounds }
;
1566 rewrite_ty(rw_info
, Some(bounds
), Some(&op
), vis
)
1568 (Item(_
) | AssocTraitItem(_
) | ForeignItem(_
), None
) => {
1569 rewrite_ty(rw_info
, Some(bounds
), ty_opt
, vis
)
1571 (AssocImplItem(_
), _
) => {
1572 let result
= if let Some(op_bounds
) = op_ty
{
1573 let op
= OpaqueType { bounds: op_bounds }
;
1574 rewrite_ty(rw_info
, Some(bounds
), Some(&op
), &DEFAULT_VISIBILITY
)
1576 rewrite_ty(rw_info
, Some(bounds
), ty_opt
, vis
)
1579 ast
::Defaultness
::Default(..) => Some(format
!("default {}", result
)),
1586 fn rewrite_ty
<R
: Rewrite
>(
1587 rw_info
: &TyAliasRewriteInfo
<'_
, '_
>,
1588 generic_bounds_opt
: Option
<&ast
::GenericBounds
>,
1590 vis
: &ast
::Visibility
,
1591 ) -> Option
<String
> {
1592 let mut result
= String
::with_capacity(128);
1593 let TyAliasRewriteInfo(
1598 where_predicates_split
,
1602 let (before_where_predicates
, after_where_predicates
) = generics
1605 .split_at(where_predicates_split
);
1606 if !after_where_predicates
.is_empty() {
1609 result
.push_str(&format
!("{}type ", format_visibility(context
, vis
)));
1610 let ident_str
= rewrite_ident(context
, ident
);
1612 if generics
.params
.is_empty() {
1613 result
.push_str(ident_str
)
1616 let g_shape
= Shape
::indented(indent
, context
.config
)
1617 .offset_left(result
.len())?
1619 let generics_str
= rewrite_generics(context
, ident_str
, generics
, g_shape
)?
;
1620 result
.push_str(&generics_str
);
1623 if let Some(bounds
) = generic_bounds_opt
{
1624 if !bounds
.is_empty() {
1626 let shape
= Shape
::indented(indent
, context
.config
).offset_left(result
.len() + 2)?
;
1627 let type_bounds
= bounds
.rewrite(context
, shape
).map(|s
| format
!(": {}", s
))?
;
1628 result
.push_str(&type_bounds
);
1632 let where_budget
= context
.budget(last_line_width(&result
));
1633 let mut option
= WhereClauseOption
::snuggled(&result
);
1635 option
.suppress_comma();
1637 let where_clause_str
= rewrite_where_clause(
1639 before_where_predicates
,
1641 context
.config
.brace_style(),
1642 Shape
::legacy(where_budget
, indent
),
1649 result
.push_str(&where_clause_str
);
1651 if let Some(ty
) = rhs
{
1652 // If there's a where clause, add a newline before the assignment. Otherwise just add a
1654 let has_where
= !before_where_predicates
.is_empty();
1656 result
.push_str(&indent
.to_string_with_newline(context
.config
));
1661 let comment_span
= context
1663 .opt_span_before(span
, "=")
1664 .map(|op_lo
| mk_sp(where_clauses
.0.1.hi(), op_lo
));
1666 let lhs
= match comment_span
{
1668 if contains_comment(context
.snippet_provider
.span_to_snippet(comment_span
)?
) =>
1670 let comment_shape
= if has_where
{
1671 Shape
::indented(indent
, context
.config
)
1673 Shape
::indented(indent
, context
.config
)
1674 .block_left(context
.config
.tab_spaces())?
1677 combine_strs_with_missing_comments(
1686 _
=> format
!("{}=", result
),
1690 let shape
= Shape
::indented(indent
, context
.config
).sub_width(1)?
;
1691 rewrite_assign_rhs(context
, lhs
, &*ty
, &RhsAssignKind
::Ty
, shape
).map(|s
| s
+ ";")
1693 Some(format
!("{};", result
))
1697 fn type_annotation_spacing(config
: &Config
) -> (&str, &str) {
1699 if config
.space_before_colon() { " " }
else { "" }
,
1700 if config
.space_after_colon() { " " }
else { "" }
,
1704 pub(crate) fn rewrite_struct_field_prefix(
1705 context
: &RewriteContext
<'_
>,
1706 field
: &ast
::FieldDef
,
1707 ) -> Option
<String
> {
1708 let vis
= format_visibility(context
, &field
.vis
);
1709 let type_annotation_spacing
= type_annotation_spacing(context
.config
);
1710 Some(match field
.ident
{
1711 Some(name
) => format
!(
1714 rewrite_ident(context
, name
),
1715 type_annotation_spacing
.0
1717 None
=> vis
.to_string(),
1721 impl Rewrite
for ast
::FieldDef
{
1722 fn rewrite(&self, context
: &RewriteContext
<'_
>, shape
: Shape
) -> Option
<String
> {
1723 rewrite_struct_field(context
, self, shape
, 0)
1727 pub(crate) fn rewrite_struct_field(
1728 context
: &RewriteContext
<'_
>,
1729 field
: &ast
::FieldDef
,
1731 lhs_max_width
: usize,
1732 ) -> Option
<String
> {
1733 if contains_skip(&field
.attrs
) {
1734 return Some(context
.snippet(field
.span()).to_owned());
1737 let type_annotation_spacing
= type_annotation_spacing(context
.config
);
1738 let prefix
= rewrite_struct_field_prefix(context
, field
)?
;
1740 let attrs_str
= field
.attrs
.rewrite(context
, shape
)?
;
1741 let attrs_extendable
= field
.ident
.is_none() && is_attributes_extendable(&attrs_str
);
1742 let missing_span
= if field
.attrs
.is_empty() {
1743 mk_sp(field
.span
.lo(), field
.span
.lo())
1745 mk_sp(field
.attrs
.last().unwrap().span
.hi(), field
.span
.lo())
1747 let mut spacing
= String
::from(if field
.ident
.is_some() {
1748 type_annotation_spacing
.1
1752 // Try to put everything on a single line.
1753 let attr_prefix
= combine_strs_with_missing_comments(
1761 let overhead
= trimmed_last_line_width(&attr_prefix
);
1762 let lhs_offset
= lhs_max_width
.saturating_sub(overhead
);
1763 for _
in 0..lhs_offset
{
1766 // In this extreme case we will be missing a space between an attribute and a field.
1767 if prefix
.is_empty() && !attrs_str
.is_empty() && attrs_extendable
&& spacing
.is_empty() {
1771 .offset_left(overhead
+ spacing
.len())
1772 .and_then(|ty_shape
| field
.ty
.rewrite(context
, ty_shape
));
1773 if let Some(ref ty
) = orig_ty
{
1774 if !ty
.contains('
\n'
) {
1775 return Some(attr_prefix
+ &spacing
+ ty
);
1779 let is_prefix_empty
= prefix
.is_empty();
1780 // We must use multiline. We are going to put attributes and a field on different lines.
1781 let field_str
= rewrite_assign_rhs(context
, prefix
, &*field
.ty
, &RhsAssignKind
::Ty
, shape
)?
;
1782 // Remove a leading white-space from `rewrite_assign_rhs()` when rewriting a tuple struct.
1783 let field_str
= if is_prefix_empty
{
1784 field_str
.trim_start()
1788 combine_strs_with_missing_comments(context
, &attrs_str
, field_str
, missing_span
, shape
, false)
1791 pub(crate) struct StaticParts
<'a
> {
1793 vis
: &'a ast
::Visibility
,
1794 ident
: symbol
::Ident
,
1796 mutability
: ast
::Mutability
,
1797 expr_opt
: Option
<&'a ptr
::P
<ast
::Expr
>>,
1798 defaultness
: Option
<ast
::Defaultness
>,
1802 impl<'a
> StaticParts
<'a
> {
1803 pub(crate) fn from_item(item
: &'a ast
::Item
) -> Self {
1804 let (defaultness
, prefix
, ty
, mutability
, expr
) = match item
.kind
{
1805 ast
::ItemKind
::Static(ref ty
, mutability
, ref expr
) => {
1806 (None
, "static", ty
, mutability
, expr
)
1808 ast
::ItemKind
::Const(defaultness
, ref ty
, ref expr
) => {
1809 (Some(defaultness
), "const", ty
, ast
::Mutability
::Not
, expr
)
1811 _
=> unreachable
!(),
1819 expr_opt
: expr
.as_ref(),
1825 pub(crate) fn from_trait_item(ti
: &'a ast
::AssocItem
) -> Self {
1826 let (defaultness
, ty
, expr_opt
) = match ti
.kind
{
1827 ast
::AssocItemKind
::Const(defaultness
, ref ty
, ref expr_opt
) => {
1828 (defaultness
, ty
, expr_opt
)
1830 _
=> unreachable
!(),
1837 mutability
: ast
::Mutability
::Not
,
1838 expr_opt
: expr_opt
.as_ref(),
1839 defaultness
: Some(defaultness
),
1844 pub(crate) fn from_impl_item(ii
: &'a ast
::AssocItem
) -> Self {
1845 let (defaultness
, ty
, expr
) = match ii
.kind
{
1846 ast
::AssocItemKind
::Const(defaultness
, ref ty
, ref expr
) => (defaultness
, ty
, expr
),
1847 _
=> unreachable
!(),
1854 mutability
: ast
::Mutability
::Not
,
1855 expr_opt
: expr
.as_ref(),
1856 defaultness
: Some(defaultness
),
1863 context
: &RewriteContext
<'_
>,
1864 static_parts
: &StaticParts
<'_
>,
1866 ) -> Option
<String
> {
1867 let colon
= colon_spaces(context
.config
);
1868 let mut prefix
= format
!(
1870 format_visibility(context
, static_parts
.vis
),
1871 static_parts
.defaultness
.map_or("", format_defaultness
),
1872 static_parts
.prefix
,
1873 format_mutability(static_parts
.mutability
),
1874 rewrite_ident(context
, static_parts
.ident
),
1879 Shape
::indented(offset
.block_only(), context
.config
).offset_left(prefix
.len() + 2)?
;
1880 let ty_str
= match static_parts
.ty
.rewrite(context
, ty_shape
) {
1881 Some(ty_str
) => ty_str
,
1883 if prefix
.ends_with(' '
) {
1886 let nested_indent
= offset
.block_indent(context
.config
);
1887 let nested_shape
= Shape
::indented(nested_indent
, context
.config
);
1888 let ty_str
= static_parts
.ty
.rewrite(context
, nested_shape
)?
;
1891 nested_indent
.to_string_with_newline(context
.config
),
1897 if let Some(expr
) = static_parts
.expr_opt
{
1898 let comments_lo
= context
.snippet_provider
.span_after(static_parts
.span
, "=");
1899 let expr_lo
= expr
.span
.lo();
1900 let comments_span
= mk_sp(comments_lo
, expr_lo
);
1902 let lhs
= format
!("{}{} =", prefix
, ty_str
);
1905 let remaining_width
= context
.budget(offset
.block_indent
+ 1);
1906 rewrite_assign_rhs_with_comments(
1910 Shape
::legacy(remaining_width
, offset
.block_only()),
1911 &RhsAssignKind
::Expr(&expr
.kind
, expr
.span
),
1912 RhsTactics
::Default
,
1916 .and_then(|res
| recover_comment_removed(res
, static_parts
.span
, context
))
1917 .map(|s
| if s
.ends_with('
;'
) { s }
else { s + ";" }
)
1919 Some(format
!("{}{};", prefix
, ty_str
))
1923 // FIXME(calebcartwright) - This is a hack around a bug in the handling of TyKind::ImplTrait.
1924 // This should be removed once that bug is resolved, with the type alias formatting using the
1925 // defined Ty for the RHS directly.
1926 // https://github.com/rust-lang/rustfmt/issues/4373
1927 // https://github.com/rust-lang/rustfmt/issues/5027
1928 struct OpaqueType
<'a
> {
1929 bounds
: &'a ast
::GenericBounds
,
1932 impl<'a
> Rewrite
for OpaqueType
<'a
> {
1933 fn rewrite(&self, context
: &RewriteContext
<'_
>, shape
: Shape
) -> Option
<String
> {
1934 let shape
= shape
.offset_left(5)?
; // `impl `
1936 .rewrite(context
, shape
)
1937 .map(|s
| format
!("impl {}", s
))
1941 impl Rewrite
for ast
::FnRetTy
{
1942 fn rewrite(&self, context
: &RewriteContext
<'_
>, shape
: Shape
) -> Option
<String
> {
1944 ast
::FnRetTy
::Default(_
) => Some(String
::new()),
1945 ast
::FnRetTy
::Ty(ref ty
) => {
1946 if context
.config
.version() == Version
::One
1947 || context
.config
.indent_style() == IndentStyle
::Visual
1949 let inner_width
= shape
.width
.checked_sub(3)?
;
1951 .rewrite(context
, Shape
::legacy(inner_width
, shape
.indent
+ 3))
1952 .map(|r
| format
!("-> {}", r
));
1955 ty
.rewrite(context
, shape
.offset_left(3)?
)
1956 .map(|s
| format
!("-> {}", s
))
1962 fn is_empty_infer(ty
: &ast
::Ty
, pat_span
: Span
) -> bool
{
1964 ast
::TyKind
::Infer
=> ty
.span
.hi() == pat_span
.hi(),
1969 /// Recover any missing comments between the param and the type.
1973 /// A 2-len tuple with the comment before the colon in first position, and the comment after the
1974 /// colon in second position.
1975 fn get_missing_param_comments(
1976 context
: &RewriteContext
<'_
>,
1980 ) -> (String
, String
) {
1981 let missing_comment_span
= mk_sp(pat_span
.hi(), ty_span
.lo());
1983 let span_before_colon
= {
1984 let missing_comment_span_hi
= context
1986 .span_before(missing_comment_span
, ":");
1987 mk_sp(pat_span
.hi(), missing_comment_span_hi
)
1989 let span_after_colon
= {
1990 let missing_comment_span_lo
= context
1992 .span_after(missing_comment_span
, ":");
1993 mk_sp(missing_comment_span_lo
, ty_span
.lo())
1996 let comment_before_colon
= rewrite_missing_comment(span_before_colon
, shape
, context
)
1997 .filter(|comment
| !comment
.is_empty())
1998 .map_or(String
::new(), |comment
| format
!(" {}", comment
));
1999 let comment_after_colon
= rewrite_missing_comment(span_after_colon
, shape
, context
)
2000 .filter(|comment
| !comment
.is_empty())
2001 .map_or(String
::new(), |comment
| format
!("{} ", comment
));
2002 (comment_before_colon
, comment_after_colon
)
2005 impl Rewrite
for ast
::Param
{
2006 fn rewrite(&self, context
: &RewriteContext
<'_
>, shape
: Shape
) -> Option
<String
> {
2007 let param_attrs_result
= self
2009 .rewrite(context
, Shape
::legacy(shape
.width
, shape
.indent
))?
;
2010 // N.B. Doc comments aren't typically valid syntax, but could appear
2011 // in the presence of certain macros - https://github.com/rust-lang/rustfmt/issues/4936
2012 let (span
, has_multiple_attr_lines
, has_doc_comments
) = if !self.attrs
.is_empty() {
2013 let num_attrs
= self.attrs
.len();
2015 mk_sp(self.attrs
[num_attrs
- 1].span
.hi(), self.pat
.span
.lo()),
2016 param_attrs_result
.contains('
\n'
),
2017 self.attrs
.iter().any(|a
| a
.is_doc_comment()),
2020 (mk_sp(self.span
.lo(), self.span
.lo()), false, false)
2023 if let Some(ref explicit_self
) = self.to_self() {
2024 rewrite_explicit_self(
2027 ¶m_attrs_result
,
2030 has_multiple_attr_lines
,
2032 } else if is_named_param(self) {
2033 let param_name
= &self
2035 .rewrite(context
, Shape
::legacy(shape
.width
, shape
.indent
))?
;
2036 let mut result
= combine_strs_with_missing_comments(
2038 ¶m_attrs_result
,
2042 !has_multiple_attr_lines
&& !has_doc_comments
,
2045 if !is_empty_infer(&*self.ty
, self.pat
.span
) {
2046 let (before_comment
, after_comment
) =
2047 get_missing_param_comments(context
, self.pat
.span
, self.ty
.span
, shape
);
2048 result
.push_str(&before_comment
);
2049 result
.push_str(colon_spaces(context
.config
));
2050 result
.push_str(&after_comment
);
2051 let overhead
= last_line_width(&result
);
2052 let max_width
= shape
.width
.checked_sub(overhead
)?
;
2053 if let Some(ty_str
) = self
2055 .rewrite(context
, Shape
::legacy(max_width
, shape
.indent
))
2057 result
.push_str(&ty_str
);
2059 let prev_str
= if param_attrs_result
.is_empty() {
2062 param_attrs_result
+ &shape
.to_string_with_newline(context
.config
)
2065 result
= combine_strs_with_missing_comments(
2071 !has_multiple_attr_lines
,
2073 result
.push_str(&before_comment
);
2074 result
.push_str(colon_spaces(context
.config
));
2075 result
.push_str(&after_comment
);
2076 let overhead
= last_line_width(&result
);
2077 let max_width
= shape
.width
.checked_sub(overhead
)?
;
2080 .rewrite(context
, Shape
::legacy(max_width
, shape
.indent
))?
;
2081 result
.push_str(&ty_str
);
2087 self.ty
.rewrite(context
, shape
)
2092 fn rewrite_explicit_self(
2093 context
: &RewriteContext
<'_
>,
2094 explicit_self
: &ast
::ExplicitSelf
,
2098 has_multiple_attr_lines
: bool
,
2099 ) -> Option
<String
> {
2100 match explicit_self
.node
{
2101 ast
::SelfKind
::Region(lt
, m
) => {
2102 let mut_str
= format_mutability(m
);
2105 let lifetime_str
= l
.rewrite(
2107 Shape
::legacy(context
.config
.max_width(), Indent
::empty()),
2109 Some(combine_strs_with_missing_comments(
2112 &format
!("&{} {}self", lifetime_str
, mut_str
),
2115 !has_multiple_attr_lines
,
2118 None
=> Some(combine_strs_with_missing_comments(
2121 &format
!("&{}self", mut_str
),
2124 !has_multiple_attr_lines
,
2128 ast
::SelfKind
::Explicit(ref ty
, mutability
) => {
2129 let type_str
= ty
.rewrite(
2131 Shape
::legacy(context
.config
.max_width(), Indent
::empty()),
2134 Some(combine_strs_with_missing_comments(
2137 &format
!("{}self: {}", format_mutability(mutability
), type_str
),
2140 !has_multiple_attr_lines
,
2143 ast
::SelfKind
::Value(mutability
) => Some(combine_strs_with_missing_comments(
2146 &format
!("{}self", format_mutability(mutability
)),
2149 !has_multiple_attr_lines
,
2154 pub(crate) fn span_lo_for_param(param
: &ast
::Param
) -> BytePos
{
2155 if param
.attrs
.is_empty() {
2156 if is_named_param(param
) {
2162 param
.attrs
[0].span
.lo()
2166 pub(crate) fn span_hi_for_param(context
: &RewriteContext
<'_
>, param
: &ast
::Param
) -> BytePos
{
2167 match param
.ty
.kind
{
2168 ast
::TyKind
::Infer
if context
.snippet(param
.ty
.span
) == "_" => param
.ty
.span
.hi(),
2169 ast
::TyKind
::Infer
if is_named_param(param
) => param
.pat
.span
.hi(),
2170 _
=> param
.ty
.span
.hi(),
2174 pub(crate) fn is_named_param(param
: &ast
::Param
) -> bool
{
2175 if let ast
::PatKind
::Ident(_
, ident
, _
) = param
.pat
.kind
{
2176 ident
.name
!= symbol
::kw
::Empty
2182 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
2183 pub(crate) enum FnBraceStyle
{
2189 // Return type is (result, force_new_line_for_brace)
2191 context
: &RewriteContext
<'_
>,
2193 ident
: symbol
::Ident
,
2196 fn_brace_style
: FnBraceStyle
,
2197 ) -> Option
<(String
, bool
, bool
)> {
2198 let mut force_new_line_for_brace
= false;
2200 let where_clause
= &fn_sig
.generics
.where_clause
;
2202 let mut result
= String
::with_capacity(1024);
2203 result
.push_str(&fn_sig
.to_str(context
));
2206 result
.push_str("fn ");
2209 let overhead
= if let FnBraceStyle
::SameLine
= fn_brace_style
{
2216 let used_width
= last_line_used_width(&result
, indent
.width());
2217 let one_line_budget
= context
.budget(used_width
+ overhead
);
2219 width
: one_line_budget
,
2223 let fd
= fn_sig
.decl
;
2224 let generics_str
= rewrite_generics(
2226 rewrite_ident(context
, ident
),
2230 result
.push_str(&generics_str
);
2232 let snuggle_angle_bracket
= generics_str
2235 .map_or(false, |l
| l
.trim_start().len() == 1);
2237 // Note that the width and indent don't really matter, we'll re-layout the
2238 // return type later anyway.
2241 .rewrite(context
, Shape
::indented(indent
, context
.config
))?
;
2243 let multi_line_ret_str
= ret_str
.contains('
\n'
);
2244 let ret_str_len
= if multi_line_ret_str { 0 }
else { ret_str.len() }
;
2247 let (one_line_budget
, multi_line_budget
, mut param_indent
) = compute_budgets_for_params(
2257 "rewrite_fn_base: one_line_budget: {}, multi_line_budget: {}, param_indent: {:?}",
2258 one_line_budget
, multi_line_budget
, param_indent
2262 // Check if vertical layout was forced.
2263 if one_line_budget
== 0
2264 && !snuggle_angle_bracket
2265 && context
.config
.indent_style() == IndentStyle
::Visual
2267 result
.push_str(¶m_indent
.to_string_with_newline(context
.config
));
2270 let params_end
= if fd
.inputs
.is_empty() {
2273 .span_after(mk_sp(fn_sig
.generics
.span
.hi(), span
.hi()), ")")
2275 let last_span
= mk_sp(fd
.inputs
[fd
.inputs
.len() - 1].span().hi(), span
.hi());
2276 context
.snippet_provider
.span_after(last_span
, ")")
2278 let params_span
= mk_sp(
2281 .span_after(mk_sp(fn_sig
.generics
.span
.hi(), span
.hi()), "("),
2284 let param_str
= rewrite_params(
2295 let put_params_in_block
= match context
.config
.indent_style() {
2296 IndentStyle
::Block
=> param_str
.contains('
\n'
) || param_str
.len() > one_line_budget
,
2298 } && !fd
.inputs
.is_empty();
2300 let mut params_last_line_contains_comment
= false;
2301 let mut no_params_and_over_max_width
= false;
2303 if put_params_in_block
{
2304 param_indent
= indent
.block_indent(context
.config
);
2305 result
.push_str(¶m_indent
.to_string_with_newline(context
.config
));
2306 result
.push_str(¶m_str
);
2307 result
.push_str(&indent
.to_string_with_newline(context
.config
));
2310 result
.push_str(¶m_str
);
2311 let used_width
= last_line_used_width(&result
, indent
.width()) + first_line_width(&ret_str
);
2312 // Put the closing brace on the next line if it overflows the max width.
2314 let closing_paren_overflow_max_width
=
2315 fd
.inputs
.is_empty() && used_width
+ 1 > context
.config
.max_width();
2316 // If the last line of params contains comment, we cannot put the closing paren
2317 // on the same line.
2318 params_last_line_contains_comment
= param_str
2321 .map_or(false, |last_line
| last_line
.contains("//"));
2323 if context
.config
.version() == Version
::Two
{
2324 if closing_paren_overflow_max_width
{
2326 result
.push_str(&indent
.to_string_with_newline(context
.config
));
2327 no_params_and_over_max_width
= true;
2328 } else if params_last_line_contains_comment
{
2329 result
.push_str(&indent
.to_string_with_newline(context
.config
));
2331 no_params_and_over_max_width
= true;
2336 if closing_paren_overflow_max_width
|| params_last_line_contains_comment
{
2337 result
.push_str(&indent
.to_string_with_newline(context
.config
));
2344 if let ast
::FnRetTy
::Ty(..) = fd
.output
{
2345 let ret_should_indent
= match context
.config
.indent_style() {
2346 // If our params are block layout then we surely must have space.
2347 IndentStyle
::Block
if put_params_in_block
|| fd
.inputs
.is_empty() => false,
2348 _
if params_last_line_contains_comment
=> false,
2349 _
if result
.contains('
\n'
) || multi_line_ret_str
=> true,
2351 // If the return type would push over the max width, then put the return type on
2352 // a new line. With the +1 for the signature length an additional space between
2353 // the closing parenthesis of the param and the arrow '->' is considered.
2354 let mut sig_length
= result
.len() + indent
.width() + ret_str_len
+ 1;
2356 // If there is no where-clause, take into account the space after the return type
2358 if where_clause
.predicates
.is_empty() {
2362 sig_length
> context
.config
.max_width()
2365 let ret_shape
= if ret_should_indent
{
2366 if context
.config
.version() == Version
::One
2367 || context
.config
.indent_style() == IndentStyle
::Visual
2369 let indent
= if param_str
.is_empty() {
2370 // Aligning with non-existent params looks silly.
2371 force_new_line_for_brace
= true;
2374 // FIXME: we might want to check that using the param indent
2375 // doesn't blow our budget, and if it does, then fallback to
2376 // the where-clause indent.
2380 result
.push_str(&indent
.to_string_with_newline(context
.config
));
2381 Shape
::indented(indent
, context
.config
)
2383 let mut ret_shape
= Shape
::indented(indent
, context
.config
);
2384 if param_str
.is_empty() {
2385 // Aligning with non-existent params looks silly.
2386 force_new_line_for_brace
= true;
2387 ret_shape
= if context
.use_block_indent() {
2388 ret_shape
.offset_left(4).unwrap_or(ret_shape
)
2390 ret_shape
.indent
= ret_shape
.indent
+ 4;
2395 result
.push_str(&ret_shape
.indent
.to_string_with_newline(context
.config
));
2399 if context
.config
.version() == Version
::Two
{
2400 if !param_str
.is_empty() || !no_params_and_over_max_width
{
2407 let ret_shape
= Shape
::indented(indent
, context
.config
);
2409 .offset_left(last_line_width(&result
))
2410 .unwrap_or(ret_shape
)
2413 if multi_line_ret_str
|| ret_should_indent
{
2414 // Now that we know the proper indent and width, we need to
2415 // re-layout the return type.
2416 let ret_str
= fd
.output
.rewrite(context
, ret_shape
)?
;
2417 result
.push_str(&ret_str
);
2419 result
.push_str(&ret_str
);
2422 // Comment between return type and the end of the decl.
2423 let snippet_lo
= fd
.output
.span().hi();
2424 if where_clause
.predicates
.is_empty() {
2425 let snippet_hi
= span
.hi();
2426 let snippet
= context
.snippet(mk_sp(snippet_lo
, snippet_hi
));
2427 // Try to preserve the layout of the original snippet.
2428 let original_starts_with_newline
= snippet
2430 .map_or(false, |i
| starts_with_newline(&snippet
[i
..]));
2431 let original_ends_with_newline
= snippet
2432 .rfind(|c
| c
!= ' '
)
2433 .map_or(false, |i
| snippet
[i
..].ends_with('
\n'
));
2434 let snippet
= snippet
.trim();
2435 if !snippet
.is_empty() {
2436 result
.push(if original_starts_with_newline
{
2441 result
.push_str(snippet
);
2442 if original_ends_with_newline
{
2443 force_new_line_for_brace
= true;
2449 let pos_before_where
= match fd
.output
{
2450 ast
::FnRetTy
::Default(..) => params_span
.hi(),
2451 ast
::FnRetTy
::Ty(ref ty
) => ty
.span
.hi(),
2454 let is_params_multi_lined
= param_str
.contains('
\n'
);
2456 let space
= if put_params_in_block
&& ret_str
.is_empty() {
2457 WhereClauseSpace
::Space
2459 WhereClauseSpace
::Newline
2461 let mut option
= WhereClauseOption
::new(fn_brace_style
== FnBraceStyle
::None
, space
);
2462 if is_params_multi_lined
{
2463 option
.veto_single_line();
2465 let where_clause_str
= rewrite_where_clause(
2467 &where_clause
.predicates
,
2469 context
.config
.brace_style(),
2470 Shape
::indented(indent
, context
.config
),
2477 // If there are neither where-clause nor return type, we may be missing comments between
2479 if where_clause_str
.is_empty() {
2480 if let ast
::FnRetTy
::Default(ret_span
) = fd
.output
{
2481 match recover_missing_comment_in_span(
2482 mk_sp(params_span
.hi(), ret_span
.hi()),
2485 last_line_width(&result
),
2487 Some(ref missing_comment
) if !missing_comment
.is_empty() => {
2488 result
.push_str(missing_comment
);
2489 force_new_line_for_brace
= true;
2496 result
.push_str(&where_clause_str
);
2498 let ends_with_comment
= last_line_contains_single_line_comment(&result
);
2499 force_new_line_for_brace
|= ends_with_comment
;
2500 force_new_line_for_brace
|=
2501 is_params_multi_lined
&& context
.config
.where_single_line() && !where_clause_str
.is_empty();
2502 Some((result
, ends_with_comment
, force_new_line_for_brace
))
2505 /// Kind of spaces to put before `where`.
2506 #[derive(Copy, Clone)]
2507 enum WhereClauseSpace
{
2516 #[derive(Copy, Clone)]
2517 struct WhereClauseOption
{
2518 suppress_comma
: bool
, // Force no trailing comma
2519 snuggle
: WhereClauseSpace
,
2520 allow_single_line
: bool
, // Try single line where-clause instead of vertical layout
2521 veto_single_line
: bool
, // Disallow a single-line where-clause.
2524 impl WhereClauseOption
{
2525 fn new(suppress_comma
: bool
, snuggle
: WhereClauseSpace
) -> WhereClauseOption
{
2529 allow_single_line
: false,
2530 veto_single_line
: false,
2534 fn snuggled(current
: &str) -> WhereClauseOption
{
2536 suppress_comma
: false,
2537 snuggle
: if last_line_width(current
) == 1 {
2538 WhereClauseSpace
::Space
2540 WhereClauseSpace
::Newline
2542 allow_single_line
: false,
2543 veto_single_line
: false,
2547 fn suppress_comma(&mut self) {
2548 self.suppress_comma
= true
2551 fn allow_single_line(&mut self) {
2552 self.allow_single_line
= true
2555 fn snuggle(&mut self) {
2556 self.snuggle
= WhereClauseSpace
::Space
2559 fn veto_single_line(&mut self) {
2560 self.veto_single_line
= true;
2565 context
: &RewriteContext
<'_
>,
2566 params
: &[ast
::Param
],
2567 one_line_budget
: usize,
2568 multi_line_budget
: usize,
2570 param_indent
: Indent
,
2573 ) -> Option
<String
> {
2574 if params
.is_empty() {
2575 let comment
= context
2579 span
.hi() - BytePos(1),
2582 return Some(comment
.to_owned());
2584 let param_items
: Vec
<_
> = itemize_list(
2585 context
.snippet_provider
,
2589 |param
| span_lo_for_param(param
),
2590 |param
| param
.ty
.span
.hi(),
2593 .rewrite(context
, Shape
::legacy(multi_line_budget
, param_indent
))
2594 .or_else(|| Some(context
.snippet(param
.span()).to_owned()))
2602 let tactic
= definitive_tactic(
2607 .to_list_tactic(param_items
.len()),
2611 let budget
= match tactic
{
2612 DefinitiveListTactic
::Horizontal
=> one_line_budget
,
2613 _
=> multi_line_budget
,
2615 let indent
= match context
.config
.indent_style() {
2616 IndentStyle
::Block
=> indent
.block_indent(context
.config
),
2617 IndentStyle
::Visual
=> param_indent
,
2619 let trailing_separator
= if variadic
{
2620 SeparatorTactic
::Never
2622 match context
.config
.indent_style() {
2623 IndentStyle
::Block
=> context
.config
.trailing_comma(),
2624 IndentStyle
::Visual
=> SeparatorTactic
::Never
,
2627 let fmt
= ListFormatting
::new(Shape
::legacy(budget
, indent
), context
.config
)
2629 .trailing_separator(trailing_separator
)
2630 .ends_with_newline(tactic
.ends_with_newline(context
.config
.indent_style()))
2631 .preserve_newline(true);
2632 write_list(¶m_items
, &fmt
)
2635 fn compute_budgets_for_params(
2636 context
: &RewriteContext
<'_
>,
2640 fn_brace_style
: FnBraceStyle
,
2641 force_vertical_layout
: bool
,
2642 ) -> Option
<(usize, usize, Indent
)> {
2644 "compute_budgets_for_params {} {:?}, {}, {:?}",
2650 // Try keeping everything on the same line.
2651 if !result
.contains('
\n'
) && !force_vertical_layout
{
2652 // 2 = `()`, 3 = `() `, space is before ret_string.
2653 let overhead
= if ret_str_len
== 0 { 2 }
else { 3 }
;
2654 let mut used_space
= indent
.width() + result
.len() + ret_str_len
+ overhead
;
2655 match fn_brace_style
{
2656 FnBraceStyle
::None
=> used_space
+= 1, // 1 = `;`
2657 FnBraceStyle
::SameLine
=> used_space
+= 2, // 2 = `{}`
2658 FnBraceStyle
::NextLine
=> (),
2660 let one_line_budget
= context
.budget(used_space
);
2662 if one_line_budget
> 0 {
2664 let (indent
, multi_line_budget
) = match context
.config
.indent_style() {
2665 IndentStyle
::Block
=> {
2666 let indent
= indent
.block_indent(context
.config
);
2667 (indent
, context
.budget(indent
.width() + 1))
2669 IndentStyle
::Visual
=> {
2670 let indent
= indent
+ result
.len() + 1;
2671 let multi_line_overhead
= match fn_brace_style
{
2672 FnBraceStyle
::SameLine
=> 4,
2675 (indent
, context
.budget(multi_line_overhead
))
2679 return Some((one_line_budget
, multi_line_budget
, indent
));
2683 // Didn't work. we must force vertical layout and put params on a newline.
2684 let new_indent
= indent
.block_indent(context
.config
);
2685 let used_space
= match context
.config
.indent_style() {
2687 IndentStyle
::Block
=> new_indent
.width() + 1,
2688 // Account for `)` and possibly ` {`.
2689 IndentStyle
::Visual
=> new_indent
.width() + if ret_str_len
== 0 { 1 }
else { 3 }
,
2691 Some((0, context
.budget(used_space
), new_indent
))
2694 fn newline_for_brace(config
: &Config
, where_clause
: &ast
::WhereClause
) -> FnBraceStyle
{
2695 let predicate_count
= where_clause
.predicates
.len();
2697 if config
.where_single_line() && predicate_count
== 1 {
2698 return FnBraceStyle
::SameLine
;
2700 let brace_style
= config
.brace_style();
2702 let use_next_line
= brace_style
== BraceStyle
::AlwaysNextLine
2703 || (brace_style
== BraceStyle
::SameLineWhere
&& predicate_count
> 0);
2705 FnBraceStyle
::NextLine
2707 FnBraceStyle
::SameLine
2711 fn rewrite_generics(
2712 context
: &RewriteContext
<'_
>,
2714 generics
: &ast
::Generics
,
2716 ) -> Option
<String
> {
2717 // FIXME: convert bounds to where-clauses where they get too big or if
2718 // there is a where-clause at all.
2720 if generics
.params
.is_empty() {
2721 return Some(ident
.to_owned());
2724 let params
= generics
.params
.iter();
2725 overflow
::rewrite_with_angle_brackets(context
, ident
, params
, shape
, generics
.span
)
2728 fn generics_shape_from_config(config
: &Config
, shape
: Shape
, offset
: usize) -> Option
<Shape
> {
2729 match config
.indent_style() {
2730 IndentStyle
::Visual
=> shape
.visual_indent(1 + offset
).sub_width(offset
+ 2),
2731 IndentStyle
::Block
=> {
2735 .block_indent(config
.tab_spaces())
2736 .with_max_width(config
)
2742 fn rewrite_where_clause_rfc_style(
2743 context
: &RewriteContext
<'_
>,
2744 predicates
: &[ast
::WherePredicate
],
2748 span_end
: Option
<BytePos
>,
2749 span_end_before_where
: BytePos
,
2750 where_clause_option
: WhereClauseOption
,
2751 ) -> Option
<String
> {
2752 let (where_keyword
, allow_single_line
) = rewrite_where_keyword(
2757 span_end_before_where
,
2758 where_clause_option
,
2762 let clause_shape
= shape
2764 .with_max_width(context
.config
)
2765 .block_left(context
.config
.tab_spaces())?
2767 let force_single_line
= context
.config
.where_single_line()
2768 && predicates
.len() == 1
2769 && !where_clause_option
.veto_single_line
;
2771 let preds_str
= rewrite_bounds_on_where_clause(
2777 where_clause_option
,
2783 if allow_single_line
&& !preds_str
.contains('
\n'
) && 6 + preds_str
.len() <= shape
.width
2784 || force_single_line
2788 clause_shape
.indent
.to_string_with_newline(context
.config
)
2791 Some(format
!("{}{}{}", where_keyword
, clause_sep
, preds_str
))
2794 /// Rewrite `where` and comment around it.
2795 fn rewrite_where_keyword(
2796 context
: &RewriteContext
<'_
>,
2797 predicates
: &[ast
::WherePredicate
],
2800 span_end_before_where
: BytePos
,
2801 where_clause_option
: WhereClauseOption
,
2802 ) -> Option
<(String
, bool
)> {
2803 let block_shape
= shape
.block().with_max_width(context
.config
);
2805 let clause_shape
= block_shape
2806 .block_left(context
.config
.tab_spaces())?
2809 let comment_separator
= |comment
: &str, shape
: Shape
| {
2810 if comment
.is_empty() {
2813 shape
.indent
.to_string_with_newline(context
.config
)
2817 let (span_before
, span_after
) =
2818 missing_span_before_after_where(span_end_before_where
, predicates
, where_span
);
2819 let (comment_before
, comment_after
) =
2820 rewrite_comments_before_after_where(context
, span_before
, span_after
, shape
)?
;
2822 let starting_newline
= match where_clause_option
.snuggle
{
2823 WhereClauseSpace
::Space
if comment_before
.is_empty() => Cow
::from(" "),
2824 WhereClauseSpace
::None
=> Cow
::from(""),
2825 _
=> block_shape
.indent
.to_string_with_newline(context
.config
),
2828 let newline_before_where
= comment_separator(&comment_before
, shape
);
2829 let newline_after_where
= comment_separator(&comment_after
, clause_shape
);
2830 let result
= format
!(
2832 starting_newline
, comment_before
, newline_before_where
, newline_after_where
, comment_after
2834 let allow_single_line
= where_clause_option
.allow_single_line
2835 && comment_before
.is_empty()
2836 && comment_after
.is_empty();
2838 Some((result
, allow_single_line
))
2841 /// Rewrite bounds on a where clause.
2842 fn rewrite_bounds_on_where_clause(
2843 context
: &RewriteContext
<'_
>,
2844 predicates
: &[ast
::WherePredicate
],
2847 span_end
: Option
<BytePos
>,
2848 where_clause_option
: WhereClauseOption
,
2849 force_single_line
: bool
,
2850 ) -> Option
<String
> {
2851 let span_start
= predicates
[0].span().lo();
2852 // If we don't have the start of the next span, then use the end of the
2853 // predicates, but that means we miss comments.
2854 let len
= predicates
.len();
2855 let end_of_preds
= predicates
[len
- 1].span().hi();
2856 let span_end
= span_end
.unwrap_or(end_of_preds
);
2857 let items
= itemize_list(
2858 context
.snippet_provider
,
2862 |pred
| pred
.span().lo(),
2863 |pred
| pred
.span().hi(),
2864 |pred
| pred
.rewrite(context
, shape
),
2869 let comma_tactic
= if where_clause_option
.suppress_comma
|| force_single_line
{
2870 SeparatorTactic
::Never
2872 context
.config
.trailing_comma()
2875 // shape should be vertical only and only if we have `force_single_line` option enabled
2876 // and the number of items of the where-clause is equal to 1
2877 let shape_tactic
= if force_single_line
{
2878 DefinitiveListTactic
::Horizontal
2880 DefinitiveListTactic
::Vertical
2883 let fmt
= ListFormatting
::new(shape
, context
.config
)
2884 .tactic(shape_tactic
)
2885 .trailing_separator(comma_tactic
)
2886 .preserve_newline(true);
2887 write_list(&items
.collect
::<Vec
<_
>>(), &fmt
)
2890 fn rewrite_where_clause(
2891 context
: &RewriteContext
<'_
>,
2892 predicates
: &[ast
::WherePredicate
],
2894 brace_style
: BraceStyle
,
2898 span_end
: Option
<BytePos
>,
2899 span_end_before_where
: BytePos
,
2900 where_clause_option
: WhereClauseOption
,
2901 ) -> Option
<String
> {
2902 if predicates
.is_empty() {
2903 return Some(String
::new());
2906 if context
.config
.indent_style() == IndentStyle
::Block
{
2907 return rewrite_where_clause_rfc_style(
2914 span_end_before_where
,
2915 where_clause_option
,
2919 let extra_indent
= Indent
::new(context
.config
.tab_spaces(), 0);
2921 let offset
= match context
.config
.indent_style() {
2922 IndentStyle
::Block
=> shape
.indent
+ extra_indent
.block_indent(context
.config
),
2923 // 6 = "where ".len()
2924 IndentStyle
::Visual
=> shape
.indent
+ extra_indent
+ 6,
2926 // FIXME: if indent_style != Visual, then the budgets below might
2927 // be out by a char or two.
2929 let budget
= context
.config
.max_width() - offset
.width();
2930 let span_start
= predicates
[0].span().lo();
2931 // If we don't have the start of the next span, then use the end of the
2932 // predicates, but that means we miss comments.
2933 let len
= predicates
.len();
2934 let end_of_preds
= predicates
[len
- 1].span().hi();
2935 let span_end
= span_end
.unwrap_or(end_of_preds
);
2936 let items
= itemize_list(
2937 context
.snippet_provider
,
2941 |pred
| pred
.span().lo(),
2942 |pred
| pred
.span().hi(),
2943 |pred
| pred
.rewrite(context
, Shape
::legacy(budget
, offset
)),
2948 let item_vec
= items
.collect
::<Vec
<_
>>();
2949 // FIXME: we don't need to collect here
2950 let tactic
= definitive_tactic(&item_vec
, ListTactic
::Vertical
, Separator
::Comma
, budget
);
2952 let mut comma_tactic
= context
.config
.trailing_comma();
2953 // Kind of a hack because we don't usually have trailing commas in where-clauses.
2954 if comma_tactic
== SeparatorTactic
::Vertical
|| where_clause_option
.suppress_comma
{
2955 comma_tactic
= SeparatorTactic
::Never
;
2958 let fmt
= ListFormatting
::new(Shape
::legacy(budget
, offset
), context
.config
)
2960 .trailing_separator(comma_tactic
)
2961 .ends_with_newline(tactic
.ends_with_newline(context
.config
.indent_style()))
2962 .preserve_newline(true);
2963 let preds_str
= write_list(&item_vec
, &fmt
)?
;
2965 let end_length
= if terminator
== "{" {
2966 // If the brace is on the next line we don't need to count it otherwise it needs two
2969 BraceStyle
::AlwaysNextLine
| BraceStyle
::SameLineWhere
=> 0,
2970 BraceStyle
::PreferSameLine
=> 2,
2972 } else if terminator
== "=" {
2978 || preds_str
.contains('
\n'
)
2979 || shape
.indent
.width() + " where ".len() + preds_str
.len() + end_length
> shape
.width
2983 (shape
.indent
+ extra_indent
).to_string(context
.config
),
2987 Some(format
!(" where {}", preds_str
))
2991 fn missing_span_before_after_where(
2992 before_item_span_end
: BytePos
,
2993 predicates
: &[ast
::WherePredicate
],
2996 let missing_span_before
= mk_sp(before_item_span_end
, where_span
.lo());
2998 let pos_after_where
= where_span
.lo() + BytePos(5);
2999 let missing_span_after
= mk_sp(pos_after_where
, predicates
[0].span().lo());
3000 (missing_span_before
, missing_span_after
)
3003 fn rewrite_comments_before_after_where(
3004 context
: &RewriteContext
<'_
>,
3005 span_before_where
: Span
,
3006 span_after_where
: Span
,
3008 ) -> Option
<(String
, String
)> {
3009 let before_comment
= rewrite_missing_comment(span_before_where
, shape
, context
)?
;
3010 let after_comment
= rewrite_missing_comment(
3012 shape
.block_indent(context
.config
.tab_spaces()),
3015 Some((before_comment
, after_comment
))
3019 context
: &RewriteContext
<'_
>,
3021 ident
: symbol
::Ident
,
3022 vis
: &ast
::Visibility
,
3025 let mut result
= String
::with_capacity(128);
3026 let shape
= Shape
::indented(offset
, context
.config
);
3028 result
.push_str(format_visibility(context
, vis
).trim());
3030 // Check for a missing comment between the visibility and the item name.
3031 let after_vis
= vis
.span
.hi();
3032 if let Some(before_item_name
) = context
3034 .opt_span_before(mk_sp(vis
.span
.lo(), ident
.span
.hi()), item_name
.trim())
3036 let missing_span
= mk_sp(after_vis
, before_item_name
);
3037 if let Some(result_with_comment
) = combine_strs_with_missing_comments(
3043 /* allow_extend */ true,
3045 result
= result_with_comment
;
3049 result
.push_str(rewrite_ident(context
, ident
));
3054 #[derive(PartialEq, Eq, Clone, Copy)]
3062 context
: &RewriteContext
<'_
>,
3063 generics
: &ast
::Generics
,
3064 brace_style
: BraceStyle
,
3065 brace_pos
: BracePos
,
3069 ) -> Option
<String
> {
3070 let shape
= Shape
::legacy(context
.budget(used_width
+ offset
.width()), offset
);
3071 let mut result
= rewrite_generics(context
, "", generics
, shape
)?
;
3073 // If the generics are not parameterized then generics.span.hi() == 0,
3074 // so we use span.lo(), which is the position after `struct Foo`.
3075 let span_end_before_where
= if !generics
.params
.is_empty() {
3080 let (same_line_brace
, missed_comments
) = if !generics
.where_clause
.predicates
.is_empty() {
3081 let budget
= context
.budget(last_line_used_width(&result
, offset
.width()));
3082 let mut option
= WhereClauseOption
::snuggled(&result
);
3083 if brace_pos
== BracePos
::None
{
3084 option
.suppress_comma
= true;
3086 let where_clause_str
= rewrite_where_clause(
3088 &generics
.where_clause
.predicates
,
3089 generics
.where_clause
.span
,
3091 Shape
::legacy(budget
, offset
.block_only()),
3095 span_end_before_where
,
3098 result
.push_str(&where_clause_str
);
3100 brace_pos
== BracePos
::ForceSameLine
|| brace_style
== BraceStyle
::PreferSameLine
,
3101 // missed comments are taken care of in #rewrite_where_clause
3106 brace_pos
== BracePos
::ForceSameLine
3107 || (result
.contains('
\n'
) && brace_style
== BraceStyle
::PreferSameLine
3108 || brace_style
!= BraceStyle
::AlwaysNextLine
)
3109 || trimmed_last_line_width(&result
) == 1,
3110 rewrite_missing_comment(
3112 span_end_before_where
,
3113 if brace_pos
== BracePos
::None
{
3116 context
.snippet_provider
.span_before(span
, "{")
3124 // add missing comments
3125 let missed_line_comments
= missed_comments
3126 .filter(|missed_comments
| !missed_comments
.is_empty())
3127 .map_or(false, |missed_comments
| {
3128 let is_block
= is_last_comment_block(&missed_comments
);
3129 let sep
= if is_block { " " }
else { "\n" }
;
3130 result
.push_str(sep
);
3131 result
.push_str(&missed_comments
);
3134 if brace_pos
== BracePos
::None
{
3135 return Some(result
);
3137 let total_used_width
= last_line_used_width(&result
, used_width
);
3138 let remaining_budget
= context
.budget(total_used_width
);
3139 // If the same line brace if forced, it indicates that we are rewriting an item with empty body,
3140 // and hence we take the closer into account as well for one line budget.
3141 // We assume that the closer has the same length as the opener.
3142 let overhead
= if brace_pos
== BracePos
::ForceSameLine
{
3149 let forbid_same_line_brace
= missed_line_comments
|| overhead
> remaining_budget
;
3150 if !forbid_same_line_brace
&& same_line_brace
{
3154 result
.push_str(&offset
.block_only().to_string(context
.config
));
3161 impl Rewrite
for ast
::ForeignItem
{
3162 fn rewrite(&self, context
: &RewriteContext
<'_
>, shape
: Shape
) -> Option
<String
> {
3163 let attrs_str
= self.attrs
.rewrite(context
, shape
)?
;
3164 // Drop semicolon or it will be interpreted as comment.
3165 // FIXME: this may be a faulty span from libsyntax.
3166 let span
= mk_sp(self.span
.lo(), self.span
.hi() - BytePos(1));
3168 let item_str
= match self.kind
{
3169 ast
::ForeignItemKind
::Fn(ref fn_kind
) => {
3176 if let Some(ref body
) = body
{
3177 let mut visitor
= FmtVisitor
::from_context(context
);
3178 visitor
.block_indent
= shape
.indent
;
3179 visitor
.last_pos
= self.span
.lo();
3180 let inner_attrs
= inner_attributes(&self.attrs
);
3181 let fn_ctxt
= visit
::FnCtxt
::Foreign
;
3183 visit
::FnKind
::Fn(fn_ctxt
, self.ident
, sig
, &self.vis
, Some(body
)),
3190 Some(visitor
.buffer
.to_owned())
3196 &FnSig
::from_method_sig(sig
, generics
, &self.vis
),
3200 .map(|(s
, _
, _
)| format
!("{};", s
))
3203 ast
::ForeignItemKind
::Static(ref ty
, mutability
, _
) => {
3204 // FIXME(#21): we're dropping potential comments in between the
3205 // function kw here.
3206 let vis
= format_visibility(context
, &self.vis
);
3207 let mut_str
= format_mutability(mutability
);
3208 let prefix
= format
!(
3212 rewrite_ident(context
, self.ident
)
3220 shape
.sub_width(1)?
,
3224 ast
::ForeignItemKind
::TyAlias(ref ty_alias
) => {
3225 let (kind
, span
) = (&ItemVisitorKind
::ForeignItem(self), self.span
);
3226 rewrite_type_alias(ty_alias
, context
, shape
.indent
, kind
, span
)
3228 ast
::ForeignItemKind
::MacCall(ref mac
) => {
3229 rewrite_macro(mac
, None
, context
, shape
, MacroPosition
::Item
)
3233 let missing_span
= if self.attrs
.is_empty() {
3234 mk_sp(self.span
.lo(), self.span
.lo())
3236 mk_sp(self.attrs
[self.attrs
.len() - 1].span
.hi(), self.span
.lo())
3238 combine_strs_with_missing_comments(
3249 /// Rewrite the attributes of an item.
3251 context
: &RewriteContext
<'_
>,
3255 ) -> Option
<String
> {
3256 let attrs
= filter_inline_attrs(&item
.attrs
, item
.span());
3257 let attrs_str
= attrs
.rewrite(context
, shape
)?
;
3259 let missed_span
= if attrs
.is_empty() {
3260 mk_sp(item
.span
.lo(), item
.span
.lo())
3262 mk_sp(attrs
[attrs
.len() - 1].span
.hi(), item
.span
.lo())
3265 let allow_extend
= if attrs
.len() == 1 {
3266 let line_len
= attrs_str
.len() + 1 + item_str
.len();
3267 !attrs
.first().unwrap().is_doc_comment()
3268 && context
.config
.inline_attribute_width() >= line_len
3273 combine_strs_with_missing_comments(
3283 /// Rewrite an inline mod.
3284 /// The given shape is used to format the mod's attributes.
3285 pub(crate) fn rewrite_mod(
3286 context
: &RewriteContext
<'_
>,
3289 ) -> Option
<String
> {
3290 let mut result
= String
::with_capacity(32);
3291 result
.push_str(&*format_visibility(context
, &item
.vis
));
3292 result
.push_str("mod ");
3293 result
.push_str(rewrite_ident(context
, item
.ident
));
3295 rewrite_attrs(context
, item
, &result
, attrs_shape
)
3298 /// Rewrite `extern crate foo;`.
3299 /// The given shape is used to format the extern crate's attributes.
3300 pub(crate) fn rewrite_extern_crate(
3301 context
: &RewriteContext
<'_
>,
3304 ) -> Option
<String
> {
3305 assert
!(is_extern_crate(item
));
3306 let new_str
= context
.snippet(item
.span
);
3307 let item_str
= if contains_comment(new_str
) {
3310 let no_whitespace
= &new_str
.split_whitespace().collect
::<Vec
<&str>>().join(" ");
3311 String
::from(&*Regex
::new(r
"\s;").unwrap().replace(no_whitespace
, ";"))
3313 rewrite_attrs(context
, item
, &item_str
, attrs_shape
)
3316 /// Returns `true` for `mod foo;`, false for `mod foo { .. }`.
3317 pub(crate) fn is_mod_decl(item
: &ast
::Item
) -> bool
{
3320 ast
::ItemKind
::Mod(_
, ast
::ModKind
::Loaded(_
, ast
::Inline
::Yes
, _
))
3324 pub(crate) fn is_use_item(item
: &ast
::Item
) -> bool
{
3325 matches
!(item
.kind
, ast
::ItemKind
::Use(_
))
3328 pub(crate) fn is_extern_crate(item
: &ast
::Item
) -> bool
{
3329 matches
!(item
.kind
, ast
::ItemKind
::ExternCrate(..))