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};
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, 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;
32 use crate::vertical::rewrite_with_alignment;
33 use crate::visitor::FmtVisitor;
34 use crate::DEFAULT_VISIBILITY;
36 fn type_annotation_separator(config: &Config) -> &str {
40 // Statements of the form
41 // let pat: ty = init;
42 impl Rewrite for ast::Local {
43 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
45 "Local::rewrite {:?} {} {:?}",
46 self, shape.width, shape.indent
49 skip_out_of_file_lines_range!(context, self.span);
51 if contains_skip(&self.attrs) {
55 let attrs_str = self.attrs.rewrite(context, shape)?;
56 let mut result = if attrs_str.is_empty() {
59 combine_strs_with_missing_comments(
64 self.attrs.last().map(|a| a.span.hi()).unwrap(),
73 let pat_shape = shape.offset_left(4)?;
75 let pat_shape = pat_shape.sub_width(1)?;
76 let pat_str = self.pat.rewrite(context, pat_shape)?;
77 result.push_str(&pat_str);
79 // String that is placed within the assignment pattern and expression.
81 let mut infix = String::with_capacity(32);
83 if let Some(ref ty) = self.ty {
84 let separator = type_annotation_separator(context.config);
85 let ty_shape = if pat_str.contains('\n') {
86 shape.with_max_width(context.config)
90 .offset_left(last_line_width(&result) + separator.len())?
94 let rewrite = ty.rewrite(context, ty_shape)?;
96 infix.push_str(separator);
97 infix.push_str(&rewrite);
100 if self.init.is_some() {
101 infix.push_str(" =");
107 result.push_str(&infix);
109 if let Some(ref ex) = self.init {
110 // 1 = trailing semicolon;
111 let nested_shape = shape.sub_width(1)?;
113 result = rewrite_assign_rhs(context, result, &**ex, nested_shape)?;
121 // FIXME convert to using rewrite style rather than visitor
122 // FIXME format modules in this style
126 unsafety: ast::Unsafe,
127 abi: Cow<'static, str>,
128 vis: Option<&'a ast::Visibility>,
129 body: Vec<BodyElement<'a>>,
134 fn from_foreign_mod(fm: &'a ast::ForeignMod, span: Span, config: &Config) -> Item<'a> {
136 unsafety: fm.unsafety,
138 ast::Extern::from_abi(fm.abi),
139 config.force_explicit_abi(),
146 .map(|i| BodyElement::ForeignItem(i))
154 enum BodyElement<'a> {
155 // Stmt(&'a ast::Stmt),
156 // Field(&'a ast::ExprField),
157 // Variant(&'a ast::Variant),
158 // Item(&'a ast::Item),
159 ForeignItem(&'a ast::ForeignItem),
162 /// Represents a fn's signature.
163 pub(crate) struct FnSig<'a> {
164 decl: &'a ast::FnDecl,
165 generics: &'a ast::Generics,
167 is_async: Cow<'a, ast::Async>,
168 constness: ast::Const,
169 defaultness: ast::Defaultness,
170 unsafety: ast::Unsafe,
171 visibility: ast::Visibility,
175 pub(crate) fn from_method_sig(
176 method_sig: &'a ast::FnSig,
177 generics: &'a ast::Generics,
178 visibility: ast::Visibility,
181 unsafety: method_sig.header.unsafety,
182 is_async: Cow::Borrowed(&method_sig.header.asyncness),
183 constness: method_sig.header.constness,
184 defaultness: ast::Defaultness::Final,
185 ext: method_sig.header.ext,
186 decl: &*method_sig.decl,
192 pub(crate) fn from_fn_kind(
193 fn_kind: &'a visit::FnKind<'_>,
194 generics: &'a ast::Generics,
195 decl: &'a ast::FnDecl,
196 defaultness: ast::Defaultness,
199 visit::FnKind::Fn(fn_ctxt, _, fn_sig, vis, _) => match fn_ctxt {
200 visit::FnCtxt::Assoc(..) => {
201 let mut fn_sig = FnSig::from_method_sig(fn_sig, generics, vis.clone());
202 fn_sig.defaultness = defaultness;
208 ext: fn_sig.header.ext,
209 constness: fn_sig.header.constness,
210 is_async: Cow::Borrowed(&fn_sig.header.asyncness),
212 unsafety: fn_sig.header.unsafety,
213 visibility: vis.clone(),
220 fn to_str(&self, context: &RewriteContext<'_>) -> String {
221 let mut result = String::with_capacity(128);
222 // Vis defaultness constness unsafety abi.
223 result.push_str(&*format_visibility(context, &self.visibility));
224 result.push_str(format_defaultness(self.defaultness));
225 result.push_str(format_constness(self.constness));
226 result.push_str(format_async(&self.is_async));
227 result.push_str(format_unsafety(self.unsafety));
228 result.push_str(&format_extern(
230 context.config.force_explicit_abi(),
237 impl<'a> FmtVisitor<'a> {
238 fn format_item(&mut self, item: &Item<'_>) {
239 self.buffer.push_str(format_unsafety(item.unsafety));
240 self.buffer.push_str(&item.abi);
242 let snippet = self.snippet(item.span);
243 let brace_pos = snippet.find_uncommented("{").unwrap();
246 if !item.body.is_empty() || contains_comment(&snippet[brace_pos..]) {
247 // FIXME: this skips comments between the extern keyword and the opening
249 self.last_pos = item.span.lo() + BytePos(brace_pos as u32 + 1);
250 self.block_indent = self.block_indent.block_indent(self.config);
252 if !item.body.is_empty() {
253 for item in &item.body {
254 self.format_body_element(item);
258 self.format_missing_no_indent(item.span.hi() - BytePos(1));
259 self.block_indent = self.block_indent.block_unindent(self.config);
260 let indent_str = self.block_indent.to_string(self.config);
261 self.push_str(&indent_str);
265 self.last_pos = item.span.hi();
268 fn format_body_element(&mut self, element: &BodyElement<'_>) {
270 BodyElement::ForeignItem(item) => self.format_foreign_item(item),
274 pub(crate) fn format_foreign_mod(&mut self, fm: &ast::ForeignMod, span: Span) {
275 let item = Item::from_foreign_mod(fm, span, self.config);
276 self.format_item(&item);
279 fn format_foreign_item(&mut self, item: &ast::ForeignItem) {
280 let rewrite = item.rewrite(&self.get_context(), self.shape());
281 let hi = item.span.hi();
282 let span = if item.attrs.is_empty() {
285 mk_sp(item.attrs[0].span.lo(), hi)
287 self.push_rewrite(span, rewrite);
291 pub(crate) fn rewrite_fn_before_block(
294 ident: symbol::Ident,
297 ) -> Option<(String, FnBraceStyle)> {
298 let context = self.get_context();
300 let mut fn_brace_style = newline_for_brace(self.config, &fn_sig.generics.where_clause);
301 let (result, _, force_newline_brace) =
302 rewrite_fn_base(&context, indent, ident, fn_sig, span, fn_brace_style)?;
305 if self.config.brace_style() == BraceStyle::AlwaysNextLine
306 || force_newline_brace
307 || last_line_width(&result) + 2 > self.shape().width
309 fn_brace_style = FnBraceStyle::NextLine
312 Some((result, fn_brace_style))
315 pub(crate) fn rewrite_required_fn(
318 ident: symbol::Ident,
320 generics: &ast::Generics,
322 ) -> Option<String> {
323 // Drop semicolon or it will be interpreted as comment.
324 let span = mk_sp(span.lo(), span.hi() - BytePos(1));
325 let context = self.get_context();
327 let (mut result, ends_with_comment, _) = rewrite_fn_base(
331 &FnSig::from_method_sig(sig, generics, DEFAULT_VISIBILITY),
336 // If `result` ends with a comment, then remember to add a newline
337 if ends_with_comment {
338 result.push_str(&indent.to_string_with_newline(context.config));
341 // Re-attach semicolon
347 pub(crate) fn single_line_fn(
351 inner_attrs: Option<&[ast::Attribute]>,
352 ) -> Option<String> {
353 if fn_str.contains('\n') || inner_attrs.map_or(false, |a| !a.is_empty()) {
357 let context = self.get_context();
359 if self.config.empty_item_single_line()
360 && is_empty_block(&context, block, None)
361 && self.block_indent.width() + fn_str.len() + 3 <= self.config.max_width()
362 && !last_line_contains_single_line_comment(fn_str)
364 return Some(format!("{} {{}}", fn_str));
367 if !self.config.fn_single_line() || !is_simple_block_stmt(&context, block, None) {
371 let res = Stmt::from_ast_node(block.stmts.first()?, true)
372 .rewrite(&self.get_context(), self.shape())?;
374 let width = self.block_indent.width() + fn_str.len() + res.len() + 5;
375 if !res.contains('\n') && width <= self.config.max_width() {
376 Some(format!("{} {{ {} }}", fn_str, res))
382 pub(crate) fn visit_static(&mut self, static_parts: &StaticParts<'_>) {
383 let rewrite = rewrite_static(&self.get_context(), static_parts, self.block_indent);
384 self.push_rewrite(static_parts.span, rewrite);
387 pub(crate) fn visit_struct(&mut self, struct_parts: &StructParts<'_>) {
388 let is_tuple = match struct_parts.def {
389 ast::VariantData::Tuple(..) => true,
392 let rewrite = format_struct(&self.get_context(), struct_parts, self.block_indent, None)
393 .map(|s| if is_tuple { s + ";" } else { s });
394 self.push_rewrite(struct_parts.span, rewrite);
397 pub(crate) fn visit_enum(
399 ident: symbol::Ident,
400 vis: &ast::Visibility,
401 enum_def: &ast::EnumDef,
402 generics: &ast::Generics,
406 format_header(&self.get_context(), "enum ", ident, vis, self.block_indent);
407 self.push_str(&enum_header);
409 let enum_snippet = self.snippet(span);
410 let brace_pos = enum_snippet.find_uncommented("{").unwrap();
411 let body_start = span.lo() + BytePos(brace_pos as u32 + 1);
412 let generics_str = format_generics(
415 self.config.brace_style(),
416 if enum_def.variants.is_empty() {
417 BracePos::ForceSameLine
422 // make a span that starts right after `enum Foo`
423 mk_sp(ident.span.hi(), body_start),
424 last_line_width(&enum_header),
427 self.push_str(&generics_str);
429 self.last_pos = body_start;
431 match self.format_variant_list(enum_def, body_start, span.hi()) {
432 Some(ref s) if enum_def.variants.is_empty() => self.push_str(s),
434 self.push_rewrite(mk_sp(body_start, span.hi()), rw);
435 self.block_indent = self.block_indent.block_unindent(self.config);
440 // Format the body of an enum definition
441 fn format_variant_list(
443 enum_def: &ast::EnumDef,
446 ) -> Option<String> {
447 if enum_def.variants.is_empty() {
448 let mut buffer = String::with_capacity(128);
450 let span = mk_sp(body_lo, body_hi - BytePos(1));
451 format_empty_struct_or_tuple(
461 let mut result = String::with_capacity(1024);
462 let original_offset = self.block_indent;
463 self.block_indent = self.block_indent.block_indent(self.config);
465 // If enum variants have discriminants, try to vertically align those,
466 // provided the discrims are not shifted too much to the right
467 let align_threshold: usize = self.config.enum_discrim_align_threshold();
468 let discr_ident_lens: Vec<usize> = enum_def
471 .filter(|var| var.disr_expr.is_some())
472 .map(|var| rewrite_ident(&self.get_context(), var.ident).len())
474 // cut the list at the point of longest discrim shorter than the threshold
475 // All of the discrims under the threshold will get padded, and all above - left as is.
476 let pad_discrim_ident_to = *discr_ident_lens
478 .filter(|&l| *l <= align_threshold)
482 let itemize_list_with = |one_line_width: usize| {
484 self.snippet_provider,
485 enum_def.variants.iter(),
489 if !f.attrs.is_empty() {
496 |f| self.format_variant(f, one_line_width, pad_discrim_ident_to),
503 let mut items: Vec<_> = itemize_list_with(self.config.struct_variant_width());
505 // If one of the variants use multiple lines, use multi-lined formatting for all variants.
506 let has_multiline_variant = items.iter().any(|item| item.inner_as_ref().contains('\n'));
507 let has_single_line_variant = items.iter().any(|item| !item.inner_as_ref().contains('\n'));
508 if has_multiline_variant && has_single_line_variant {
509 items = itemize_list_with(0);
512 let shape = self.shape().sub_width(2)?;
513 let fmt = ListFormatting::new(shape, self.config)
514 .trailing_separator(self.config.trailing_comma())
515 .preserve_newline(true);
517 let list = write_list(&items, &fmt)?;
518 result.push_str(&list);
519 result.push_str(&original_offset.to_string_with_newline(self.config));
524 // Variant of an enum.
527 field: &ast::Variant,
528 one_line_width: usize,
529 pad_discrim_ident_to: usize,
530 ) -> Option<String> {
531 if contains_skip(&field.attrs) {
532 let lo = field.attrs[0].span.lo();
533 let span = mk_sp(lo, field.span.hi());
534 return Some(self.snippet(span).to_owned());
537 let context = self.get_context();
539 let shape = self.shape().sub_width(1)?;
540 let attrs_str = field.attrs.rewrite(&context, shape)?;
544 .map_or(field.span.lo(), |attr| attr.span.hi());
545 let span = mk_sp(lo, field.span.lo());
547 let variant_body = match field.data {
548 ast::VariantData::Tuple(..) | ast::VariantData::Struct(..) => format_struct(
550 &StructParts::from_variant(field),
552 Some(one_line_width),
554 ast::VariantData::Unit(..) => rewrite_ident(&context, field.ident).to_owned(),
557 let variant_body = if let Some(ref expr) = field.disr_expr {
558 let lhs = format!("{:1$} =", variant_body, pad_discrim_ident_to);
559 rewrite_assign_rhs_with(
564 RhsTactics::AllowOverflow,
570 combine_strs_with_missing_comments(&context, &attrs_str, &variant_body, span, shape, false)
573 fn visit_impl_items(&mut self, items: &[ptr::P<ast::AssocItem>]) {
574 if self.get_context().config.reorder_impl_items() {
575 // Create visitor for each items, then reorder them.
576 let mut buffer = vec![];
578 self.visit_impl_item(item);
579 buffer.push((self.buffer.clone(), item.clone()));
583 fn is_type(ty: &Option<rustc_ast::ptr::P<ast::Ty>>) -> bool {
584 if let Some(lty) = ty {
585 if let ast::TyKind::ImplTrait(..) = lty.kind {
592 fn is_opaque(ty: &Option<rustc_ast::ptr::P<ast::Ty>>) -> bool {
597 a: &Option<rustc_ast::ptr::P<ast::Ty>>,
598 b: &Option<rustc_ast::ptr::P<ast::Ty>>,
600 is_type(a) && is_type(b)
604 a: &Option<rustc_ast::ptr::P<ast::Ty>>,
605 b: &Option<rustc_ast::ptr::P<ast::Ty>>,
607 is_opaque(a) && is_opaque(b)
610 // In rustc-ap-v638 the `OpaqueTy` AssocItemKind variant was removed but
611 // we still need to differentiate to maintain sorting order.
613 // type -> opaque -> const -> macro -> method
614 use crate::ast::AssocItemKind::*;
615 fn need_empty_line(a: &ast::AssocItemKind, b: &ast::AssocItemKind) -> bool {
617 (TyAlias(lty), TyAlias(rty))
618 if both_type(<y.3, &rty.3) || both_opaque(<y.3, &rty.3) =>
622 (Const(..), Const(..)) => false,
627 buffer.sort_by(|(_, a), (_, b)| match (&a.kind, &b.kind) {
628 (TyAlias(lty), TyAlias(rty))
629 if both_type(<y.3, &rty.3) || both_opaque(<y.3, &rty.3) =>
631 a.ident.as_str().cmp(&b.ident.as_str())
633 (Const(..), Const(..)) | (MacCall(..), MacCall(..)) => {
634 a.ident.as_str().cmp(&b.ident.as_str())
636 (Fn(..), Fn(..)) => a.span.lo().cmp(&b.span.lo()),
637 (TyAlias(ty), _) if is_type(&ty.3) => Ordering::Less,
638 (_, TyAlias(ty)) if is_type(&ty.3) => Ordering::Greater,
639 (TyAlias(..), _) => Ordering::Less,
640 (_, TyAlias(..)) => Ordering::Greater,
641 (Const(..), _) => Ordering::Less,
642 (_, Const(..)) => Ordering::Greater,
643 (MacCall(..), _) => Ordering::Less,
644 (_, MacCall(..)) => Ordering::Greater,
646 let mut prev_kind = None;
647 for (buf, item) in buffer {
648 // Make sure that there are at least a single empty line between
649 // different impl items.
652 .map_or(false, |prev_kind| need_empty_line(prev_kind, &item.kind))
656 let indent_str = self.block_indent.to_string_with_newline(self.config);
657 self.push_str(&indent_str);
658 self.push_str(buf.trim());
659 prev_kind = Some(item.kind.clone());
663 self.visit_impl_item(item);
669 pub(crate) fn format_impl(
670 context: &RewriteContext<'_>,
673 ) -> Option<String> {
674 if let ast::ItemKind::Impl(impl_kind) = &item.kind {
681 let mut result = String::with_capacity(128);
682 let ref_and_type = format_impl_ref_and_type(context, item, offset)?;
683 let sep = offset.to_string_with_newline(context.config);
684 result.push_str(&ref_and_type);
686 let where_budget = if result.contains('\n') {
687 context.config.max_width()
689 context.budget(last_line_width(&result))
692 let mut option = WhereClauseOption::snuggled(&ref_and_type);
693 let snippet = context.snippet(item.span);
694 let open_pos = snippet.find_uncommented("{")? + 1;
695 if !contains_comment(&snippet[open_pos..])
697 && generics.where_clause.predicates.len() == 1
698 && !result.contains('\n')
700 option.suppress_comma();
702 option.allow_single_line();
705 let missing_span = mk_sp(self_ty.span.hi(), item.span.hi());
706 let where_span_end = context.snippet_provider.opt_span_before(missing_span, "{");
707 let where_clause_str = rewrite_where_clause(
709 &generics.where_clause,
710 context.config.brace_style(),
711 Shape::legacy(where_budget, offset.block_only()),
719 // If there is no where-clause, we may have missing comments between the trait name and
720 // the opening brace.
721 if generics.where_clause.predicates.is_empty() {
722 if let Some(hi) = where_span_end {
723 match recover_missing_comment_in_span(
724 mk_sp(self_ty.span.hi(), hi),
725 Shape::indented(offset, context.config),
727 last_line_width(&result),
729 Some(ref missing_comment) if !missing_comment.is_empty() => {
730 result.push_str(missing_comment);
737 if is_impl_single_line(context, items.as_slice(), &result, &where_clause_str, item)? {
738 result.push_str(&where_clause_str);
739 if where_clause_str.contains('\n') || last_line_contains_single_line_comment(&result) {
740 // if the where_clause contains extra comments AND
741 // there is only one where-clause predicate
742 // recover the suppressed comma in single line where_clause formatting
743 if generics.where_clause.predicates.len() == 1 {
744 result.push_str(",");
746 result.push_str(&format!("{}{{{}}}", sep, sep));
748 result.push_str(" {}");
753 result.push_str(&where_clause_str);
755 let need_newline = last_line_contains_single_line_comment(&result) || result.contains('\n');
756 match context.config.brace_style() {
757 _ if need_newline => result.push_str(&sep),
758 BraceStyle::AlwaysNextLine => result.push_str(&sep),
759 BraceStyle::PreferSameLine => result.push(' '),
760 BraceStyle::SameLineWhere => {
761 if !where_clause_str.is_empty() {
762 result.push_str(&sep);
770 // this is an impl body snippet(impl SampleImpl { /* here */ })
771 let lo = max(self_ty.span.hi(), generics.where_clause.span.hi());
772 let snippet = context.snippet(mk_sp(lo, item.span.hi()));
773 let open_pos = snippet.find_uncommented("{")? + 1;
775 if !items.is_empty() || contains_comment(&snippet[open_pos..]) {
776 let mut visitor = FmtVisitor::from_context(context);
777 let item_indent = offset.block_only().block_indent(context.config);
778 visitor.block_indent = item_indent;
779 visitor.last_pos = lo + BytePos(open_pos as u32);
781 visitor.visit_attrs(&item.attrs, ast::AttrStyle::Inner);
782 visitor.visit_impl_items(items);
784 visitor.format_missing(item.span.hi() - BytePos(1));
786 let inner_indent_str = visitor.block_indent.to_string_with_newline(context.config);
787 let outer_indent_str = offset.block_only().to_string_with_newline(context.config);
789 result.push_str(&inner_indent_str);
790 result.push_str(visitor.buffer.trim());
791 result.push_str(&outer_indent_str);
792 } else if need_newline || !context.config.empty_item_single_line() {
793 result.push_str(&sep);
804 fn is_impl_single_line(
805 context: &RewriteContext<'_>,
806 items: &[ptr::P<ast::AssocItem>],
808 where_clause_str: &str,
811 let snippet = context.snippet(item.span);
812 let open_pos = snippet.find_uncommented("{")? + 1;
815 context.config.empty_item_single_line()
817 && !result.contains('\n')
818 && result.len() + where_clause_str.len() <= context.config.max_width()
819 && !contains_comment(&snippet[open_pos..]),
823 fn format_impl_ref_and_type(
824 context: &RewriteContext<'_>,
827 ) -> Option<String> {
828 if let ast::ItemKind::Impl(impl_kind) = &item.kind {
835 of_trait: ref trait_ref,
839 let mut result = String::with_capacity(128);
841 result.push_str(&format_visibility(context, &item.vis));
842 result.push_str(format_defaultness(defaultness));
843 result.push_str(format_unsafety(unsafety));
845 let shape = if context.config.version() == Version::Two {
846 Shape::indented(offset + last_line_width(&result), context.config)
848 generics_shape_from_config(
850 Shape::indented(offset + last_line_width(&result), context.config),
854 let generics_str = rewrite_generics(context, "impl", generics, shape)?;
855 result.push_str(&generics_str);
856 result.push_str(format_constness_right(constness));
858 let polarity_str = match polarity {
859 ast::ImplPolarity::Negative(_) => "!",
860 ast::ImplPolarity::Positive => "",
863 let polarity_overhead;
864 let trait_ref_overhead;
865 if let Some(ref trait_ref) = *trait_ref {
866 let result_len = last_line_width(&result);
867 result.push_str(&rewrite_trait_ref(
874 polarity_overhead = 0; // already written
875 trait_ref_overhead = " for".len();
877 polarity_overhead = polarity_str.len();
878 trait_ref_overhead = 0;
881 // Try to put the self type in a single line.
882 let curly_brace_overhead = if generics.where_clause.predicates.is_empty() {
883 // If there is no where-clause adapt budget for type formatting to take space and curly
884 // brace into account.
885 match context.config.brace_style() {
886 BraceStyle::AlwaysNextLine => 0,
892 let used_space = last_line_width(&result)
895 + curly_brace_overhead;
896 // 1 = space before the type.
897 let budget = context.budget(used_space + 1);
898 if let Some(self_ty_str) = self_ty.rewrite(context, Shape::legacy(budget, offset)) {
899 if !self_ty_str.contains('\n') {
900 if trait_ref.is_some() {
901 result.push_str(" for ");
904 result.push_str(polarity_str);
906 result.push_str(&self_ty_str);
911 // Couldn't fit the self type on a single line, put it on a new line.
913 // Add indentation of one additional tab.
914 let new_line_offset = offset.block_indent(context.config);
915 result.push_str(&new_line_offset.to_string(context.config));
916 if trait_ref.is_some() {
917 result.push_str("for ");
919 result.push_str(polarity_str);
921 let budget = context.budget(last_line_width(&result) + polarity_overhead);
922 let type_offset = match context.config.indent_style() {
923 IndentStyle::Visual => new_line_offset + trait_ref_overhead,
924 IndentStyle::Block => new_line_offset,
926 result.push_str(&*self_ty.rewrite(context, Shape::legacy(budget, type_offset))?);
933 fn rewrite_trait_ref(
934 context: &RewriteContext<'_>,
935 trait_ref: &ast::TraitRef,
939 ) -> Option<String> {
940 // 1 = space between generics and trait_ref
941 let used_space = 1 + polarity_str.len() + result_len;
942 let shape = Shape::indented(offset + used_space, context.config);
943 if let Some(trait_ref_str) = trait_ref.rewrite(context, shape) {
944 if !trait_ref_str.contains('\n') {
945 return Some(format!(" {}{}", polarity_str, trait_ref_str));
948 // We could not make enough space for trait_ref, so put it on new line.
949 let offset = offset.block_indent(context.config);
950 let shape = Shape::indented(offset, context.config);
951 let trait_ref_str = trait_ref.rewrite(context, shape)?;
954 offset.to_string_with_newline(context.config),
960 pub(crate) struct StructParts<'a> {
962 ident: symbol::Ident,
963 vis: &'a ast::Visibility,
964 def: &'a ast::VariantData,
965 generics: Option<&'a ast::Generics>,
969 impl<'a> StructParts<'a> {
970 fn format_header(&self, context: &RewriteContext<'_>, offset: Indent) -> String {
971 format_header(context, self.prefix, self.ident, self.vis, offset)
974 pub(crate) fn from_variant(variant: &'a ast::Variant) -> Self {
977 ident: variant.ident,
978 vis: &DEFAULT_VISIBILITY,
985 pub(crate) fn from_item(item: &'a ast::Item) -> Self {
986 let (prefix, def, generics) = match item.kind {
987 ast::ItemKind::Struct(ref def, ref generics) => ("struct ", def, generics),
988 ast::ItemKind::Union(ref def, ref generics) => ("union ", def, generics),
996 generics: Some(generics),
1003 context: &RewriteContext<'_>,
1004 struct_parts: &StructParts<'_>,
1006 one_line_width: Option<usize>,
1007 ) -> Option<String> {
1008 match *struct_parts.def {
1009 ast::VariantData::Unit(..) => format_unit_struct(context, struct_parts, offset),
1010 ast::VariantData::Tuple(ref fields, _) => {
1011 format_tuple_struct(context, struct_parts, fields, offset)
1013 ast::VariantData::Struct(ref fields, _) => {
1014 format_struct_struct(context, struct_parts, fields, offset, one_line_width)
1019 pub(crate) fn format_trait(
1020 context: &RewriteContext<'_>,
1023 ) -> Option<String> {
1024 if let ast::ItemKind::Trait(trait_kind) = &item.kind {
1025 let ast::TraitKind(is_auto, unsafety, ref generics, ref generic_bounds, ref trait_items) =
1027 let mut result = String::with_capacity(128);
1028 let header = format!(
1030 format_visibility(context, &item.vis),
1031 format_unsafety(unsafety),
1032 format_auto(is_auto),
1034 result.push_str(&header);
1036 let body_lo = context.snippet_provider.span_after(item.span, "{");
1038 let shape = Shape::indented(offset, context.config).offset_left(result.len())?;
1040 rewrite_generics(context, rewrite_ident(context, item.ident), generics, shape)?;
1041 result.push_str(&generics_str);
1043 // FIXME(#2055): rustfmt fails to format when there are comments between trait bounds.
1044 if !generic_bounds.is_empty() {
1045 let ident_hi = context
1047 .span_after(item.span, &item.ident.as_str());
1048 let bound_hi = generic_bounds.last().unwrap().span().hi();
1049 let snippet = context.snippet(mk_sp(ident_hi, bound_hi));
1050 if contains_comment(snippet) {
1054 result = rewrite_assign_rhs_with(
1059 RhsTactics::ForceNextLineWithoutIndent,
1063 // Rewrite where-clause.
1064 if !generics.where_clause.predicates.is_empty() {
1065 let where_on_new_line = context.config.indent_style() != IndentStyle::Block;
1067 let where_budget = context.budget(last_line_width(&result));
1068 let pos_before_where = if generic_bounds.is_empty() {
1069 generics.where_clause.span.lo()
1071 generic_bounds[generic_bounds.len() - 1].span().hi()
1073 let option = WhereClauseOption::snuggled(&generics_str);
1074 let where_clause_str = rewrite_where_clause(
1076 &generics.where_clause,
1077 context.config.brace_style(),
1078 Shape::legacy(where_budget, offset.block_only()),
1085 // If the where-clause cannot fit on the same line,
1086 // put the where-clause on a new line
1087 if !where_clause_str.contains('\n')
1088 && last_line_width(&result) + where_clause_str.len() + offset.width()
1089 > context.config.comment_width()
1091 let width = offset.block_indent + context.config.tab_spaces() - 1;
1092 let where_indent = Indent::new(0, width);
1093 result.push_str(&where_indent.to_string_with_newline(context.config));
1095 result.push_str(&where_clause_str);
1097 let item_snippet = context.snippet(item.span);
1098 if let Some(lo) = item_snippet.find('/') {
1100 let comment_hi = body_lo - BytePos(1);
1101 let comment_lo = item.span.lo() + BytePos(lo as u32);
1102 if comment_lo < comment_hi {
1103 match recover_missing_comment_in_span(
1104 mk_sp(comment_lo, comment_hi),
1105 Shape::indented(offset, context.config),
1107 last_line_width(&result),
1109 Some(ref missing_comment) if !missing_comment.is_empty() => {
1110 result.push_str(missing_comment);
1118 match context.config.brace_style() {
1119 _ if last_line_contains_single_line_comment(&result)
1120 || last_line_width(&result) + 2 > context.budget(offset.width()) =>
1122 result.push_str(&offset.to_string_with_newline(context.config));
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() && !trait_items.is_empty())
1132 result.push_str(&offset.to_string_with_newline(context.config));
1140 let block_span = mk_sp(generics.where_clause.span.hi(), item.span.hi());
1141 let snippet = context.snippet(block_span);
1142 let open_pos = snippet.find_uncommented("{")? + 1;
1143 let outer_indent_str = offset.block_only().to_string_with_newline(context.config);
1145 if !trait_items.is_empty() || contains_comment(&snippet[open_pos..]) {
1146 let mut visitor = FmtVisitor::from_context(context);
1147 visitor.block_indent = offset.block_only().block_indent(context.config);
1148 visitor.last_pos = block_span.lo() + BytePos(open_pos as u32);
1150 for item in trait_items {
1151 visitor.visit_trait_item(item);
1154 visitor.format_missing(item.span.hi() - BytePos(1));
1156 let inner_indent_str = visitor.block_indent.to_string_with_newline(context.config);
1158 result.push_str(&inner_indent_str);
1159 result.push_str(visitor.buffer.trim());
1160 result.push_str(&outer_indent_str);
1161 } else if result.contains('\n') {
1162 result.push_str(&outer_indent_str);
1172 struct OpaqueTypeBounds<'a> {
1173 generic_bounds: &'a ast::GenericBounds,
1176 impl<'a> Rewrite for OpaqueTypeBounds<'a> {
1177 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
1179 .rewrite(context, shape)
1180 .map(|s| format!("impl {}", s))
1184 pub(crate) struct TraitAliasBounds<'a> {
1185 generic_bounds: &'a ast::GenericBounds,
1186 generics: &'a ast::Generics,
1189 impl<'a> Rewrite for TraitAliasBounds<'a> {
1190 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
1191 let generic_bounds_str = self.generic_bounds.rewrite(context, shape)?;
1193 let mut option = WhereClauseOption::new(true, WhereClauseSpace::None);
1194 option.allow_single_line();
1196 let where_str = rewrite_where_clause(
1198 &self.generics.where_clause,
1199 context.config.brace_style(),
1204 self.generics.where_clause.span.lo(),
1208 let fits_single_line = !generic_bounds_str.contains('\n')
1209 && !where_str.contains('\n')
1210 && generic_bounds_str.len() + where_str.len() + 1 <= shape.width;
1211 let space = if generic_bounds_str.is_empty() || where_str.is_empty() {
1213 } else if fits_single_line {
1216 shape.indent.to_string_with_newline(&context.config)
1219 Some(format!("{}{}{}", generic_bounds_str, space, where_str))
1223 pub(crate) fn format_trait_alias(
1224 context: &RewriteContext<'_>,
1225 ident: symbol::Ident,
1226 vis: &ast::Visibility,
1227 generics: &ast::Generics,
1228 generic_bounds: &ast::GenericBounds,
1230 ) -> Option<String> {
1231 let alias = rewrite_ident(context, ident);
1232 // 6 = "trait ", 2 = " ="
1233 let g_shape = shape.offset_left(6)?.sub_width(2)?;
1234 let generics_str = rewrite_generics(context, &alias, generics, g_shape)?;
1235 let vis_str = format_visibility(context, vis);
1236 let lhs = format!("{}trait {} =", vis_str, generics_str);
1238 let trait_alias_bounds = TraitAliasBounds {
1242 rewrite_assign_rhs(context, lhs, &trait_alias_bounds, shape.sub_width(1)?).map(|s| s + ";")
1245 fn format_unit_struct(
1246 context: &RewriteContext<'_>,
1247 p: &StructParts<'_>,
1249 ) -> Option<String> {
1250 let header_str = format_header(context, p.prefix, p.ident, p.vis, offset);
1251 let generics_str = if let Some(generics) = p.generics {
1252 let hi = context.snippet_provider.span_before(p.span, ";");
1256 context.config.brace_style(),
1259 // make a span that starts right after `struct Foo`
1260 mk_sp(p.ident.span.hi(), hi),
1261 last_line_width(&header_str),
1266 Some(format!("{}{};", header_str, generics_str))
1269 pub(crate) fn format_struct_struct(
1270 context: &RewriteContext<'_>,
1271 struct_parts: &StructParts<'_>,
1272 fields: &[ast::FieldDef],
1274 one_line_width: Option<usize>,
1275 ) -> Option<String> {
1276 let mut result = String::with_capacity(1024);
1277 let span = struct_parts.span;
1279 let header_str = struct_parts.format_header(context, offset);
1280 result.push_str(&header_str);
1282 let header_hi = struct_parts.ident.span.hi();
1283 let body_lo = context.snippet_provider.span_after(span, "{");
1285 let generics_str = match struct_parts.generics {
1286 Some(g) => format_generics(
1289 context.config.brace_style(),
1290 if fields.is_empty() {
1291 BracePos::ForceSameLine
1296 // make a span that starts right after `struct Foo`
1297 mk_sp(header_hi, body_lo),
1298 last_line_width(&result),
1301 // 3 = ` {}`, 2 = ` {`.
1302 let overhead = if fields.is_empty() { 3 } else { 2 };
1303 if (context.config.brace_style() == BraceStyle::AlwaysNextLine && !fields.is_empty())
1304 || context.config.max_width() < overhead + result.len()
1306 format!("\n{}{{", offset.block_only().to_string(context.config))
1313 let overhead = if fields.is_empty() { 1 } else { 0 };
1314 let total_width = result.len() + generics_str.len() + overhead;
1315 if !generics_str.is_empty()
1316 && !generics_str.contains('\n')
1317 && total_width > context.config.max_width()
1320 result.push_str(&offset.to_string(context.config));
1321 result.push_str(generics_str.trim_start());
1323 result.push_str(&generics_str);
1326 if fields.is_empty() {
1327 let inner_span = mk_sp(body_lo, span.hi() - BytePos(1));
1328 format_empty_struct_or_tuple(context, inner_span, offset, &mut result, "", "}");
1329 return Some(result);
1333 let one_line_budget = context.budget(result.len() + 3 + offset.width());
1334 let one_line_budget =
1335 one_line_width.map_or(0, |one_line_width| min(one_line_width, one_line_budget));
1337 let items_str = rewrite_with_alignment(
1340 Shape::indented(offset.block_indent(context.config), context.config).sub_width(1)?,
1341 mk_sp(body_lo, span.hi()),
1345 if !items_str.contains('\n')
1346 && !result.contains('\n')
1347 && items_str.len() <= one_line_budget
1348 && !last_line_contains_single_line_comment(&items_str)
1350 Some(format!("{} {} }}", result, items_str))
1356 .block_indent(context.config)
1357 .to_string(context.config),
1359 offset.to_string(context.config)
1364 fn get_bytepos_after_visibility(vis: &ast::Visibility, default_span: Span) -> BytePos {
1366 ast::VisibilityKind::Crate(..) | ast::VisibilityKind::Restricted { .. } => vis.span.hi(),
1367 _ => default_span.lo(),
1371 // Format tuple or struct without any fields. We need to make sure that the comments
1372 // inside the delimiters are preserved.
1373 fn format_empty_struct_or_tuple(
1374 context: &RewriteContext<'_>,
1377 result: &mut String,
1381 // 3 = " {}" or "();"
1382 let used_width = last_line_used_width(&result, offset.width()) + 3;
1383 if used_width > context.config.max_width() {
1384 result.push_str(&offset.to_string_with_newline(context.config))
1386 result.push_str(opener);
1387 match rewrite_missing_comment(span, Shape::indented(offset, context.config), context) {
1388 Some(ref s) if s.is_empty() => (),
1390 if !is_single_line(s) || first_line_contains_single_line_comment(s) {
1391 let nested_indent_str = offset
1392 .block_indent(context.config)
1393 .to_string_with_newline(context.config);
1394 result.push_str(&nested_indent_str);
1397 if last_line_contains_single_line_comment(s) {
1398 result.push_str(&offset.to_string_with_newline(context.config));
1401 None => result.push_str(context.snippet(span)),
1403 result.push_str(closer);
1406 fn format_tuple_struct(
1407 context: &RewriteContext<'_>,
1408 struct_parts: &StructParts<'_>,
1409 fields: &[ast::FieldDef],
1411 ) -> Option<String> {
1412 let mut result = String::with_capacity(1024);
1413 let span = struct_parts.span;
1415 let header_str = struct_parts.format_header(context, offset);
1416 result.push_str(&header_str);
1418 let body_lo = if fields.is_empty() {
1419 let lo = get_bytepos_after_visibility(struct_parts.vis, span);
1422 .span_after(mk_sp(lo, span.hi()), "(")
1426 let body_hi = if fields.is_empty() {
1429 .span_after(mk_sp(body_lo, span.hi()), ")")
1431 // This is a dirty hack to work around a missing `)` from the span of the last field.
1432 let last_arg_span = fields[fields.len() - 1].span;
1435 .opt_span_after(mk_sp(last_arg_span.hi(), span.hi()), ")")
1436 .unwrap_or_else(|| last_arg_span.hi())
1439 let where_clause_str = match struct_parts.generics {
1441 let budget = context.budget(last_line_width(&header_str));
1442 let shape = Shape::legacy(budget, offset);
1443 let generics_str = rewrite_generics(context, "", generics, shape)?;
1444 result.push_str(&generics_str);
1446 let where_budget = context.budget(last_line_width(&result));
1447 let option = WhereClauseOption::new(true, WhereClauseSpace::Newline);
1448 rewrite_where_clause(
1450 &generics.where_clause,
1451 context.config.brace_style(),
1452 Shape::legacy(where_budget, offset.block_only()),
1460 None => "".to_owned(),
1463 if fields.is_empty() {
1464 let body_hi = context
1466 .span_before(mk_sp(body_lo, span.hi()), ")");
1467 let inner_span = mk_sp(body_lo, body_hi);
1468 format_empty_struct_or_tuple(context, inner_span, offset, &mut result, "(", ")");
1470 let shape = Shape::indented(offset, context.config).sub_width(1)?;
1471 result = overflow::rewrite_with_parens(
1477 context.config.fn_call_width(),
1482 if !where_clause_str.is_empty()
1483 && !where_clause_str.contains('\n')
1484 && (result.contains('\n')
1485 || offset.block_indent + result.len() + where_clause_str.len() + 1
1486 > context.config.max_width())
1488 // We need to put the where-clause on a new line, but we didn't
1489 // know that earlier, so the where-clause will not be indented properly.
1492 &(offset.block_only() + (context.config.tab_spaces() - 1)).to_string(context.config),
1495 result.push_str(&where_clause_str);
1500 fn rewrite_type<R: Rewrite>(
1501 context: &RewriteContext<'_>,
1503 ident: symbol::Ident,
1504 vis: &ast::Visibility,
1505 generics: &ast::Generics,
1506 generic_bounds_opt: Option<&ast::GenericBounds>,
1509 ) -> Option<String> {
1510 let mut result = String::with_capacity(128);
1511 result.push_str(&format!("{}type ", format_visibility(context, vis)));
1512 let ident_str = rewrite_ident(context, ident);
1514 if generics.params.is_empty() {
1515 result.push_str(ident_str)
1518 let g_shape = Shape::indented(indent, context.config)
1519 .offset_left(result.len())?
1521 let generics_str = rewrite_generics(context, ident_str, generics, g_shape)?;
1522 result.push_str(&generics_str);
1525 if let Some(bounds) = generic_bounds_opt {
1526 if !bounds.is_empty() {
1528 let shape = Shape::indented(indent, context.config).offset_left(result.len() + 2)?;
1529 let type_bounds = bounds.rewrite(context, shape).map(|s| format!(": {}", s))?;
1530 result.push_str(&type_bounds);
1534 let where_budget = context.budget(last_line_width(&result));
1535 let mut option = WhereClauseOption::snuggled(&result);
1537 option.suppress_comma();
1539 let where_clause_str = rewrite_where_clause(
1541 &generics.where_clause,
1542 context.config.brace_style(),
1543 Shape::legacy(where_budget, indent),
1550 result.push_str(&where_clause_str);
1552 if let Some(ty) = rhs {
1553 // If there's a where clause, add a newline before the assignment. Otherwise just add a
1555 let has_where = !generics.where_clause.predicates.is_empty();
1557 result.push_str(&indent.to_string_with_newline(context.config));
1562 let comment_span = context
1564 .opt_span_before(span, "=")
1565 .map(|op_lo| mk_sp(generics.where_clause.span.hi(), op_lo));
1567 let lhs = match comment_span {
1569 if contains_comment(context.snippet_provider.span_to_snippet(comment_span)?) =>
1571 let comment_shape = if has_where {
1572 Shape::indented(indent, context.config)
1574 Shape::indented(indent, context.config)
1575 .block_left(context.config.tab_spaces())?
1578 combine_strs_with_missing_comments(
1587 _ => format!("{}=", result),
1591 let shape = Shape::indented(indent, context.config).sub_width(1)?;
1592 rewrite_assign_rhs(context, lhs, &*ty, shape).map(|s| s + ";")
1594 Some(format!("{};", result))
1598 pub(crate) fn rewrite_opaque_type(
1599 context: &RewriteContext<'_>,
1601 ident: symbol::Ident,
1602 generic_bounds: &ast::GenericBounds,
1603 generics: &ast::Generics,
1604 vis: &ast::Visibility,
1606 ) -> Option<String> {
1607 let opaque_type_bounds = OpaqueTypeBounds { generic_bounds };
1614 Some(generic_bounds),
1615 Some(&opaque_type_bounds),
1620 fn type_annotation_spacing(config: &Config) -> (&str, &str) {
1622 if config.space_before_colon() { " " } else { "" },
1623 if config.space_after_colon() { " " } else { "" },
1627 pub(crate) fn rewrite_struct_field_prefix(
1628 context: &RewriteContext<'_>,
1629 field: &ast::FieldDef,
1630 ) -> Option<String> {
1631 let vis = format_visibility(context, &field.vis);
1632 let type_annotation_spacing = type_annotation_spacing(context.config);
1633 Some(match field.ident {
1634 Some(name) => format!(
1637 rewrite_ident(context, name),
1638 type_annotation_spacing.0
1640 None => vis.to_string(),
1644 impl Rewrite for ast::FieldDef {
1645 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
1646 rewrite_struct_field(context, self, shape, 0)
1650 pub(crate) fn rewrite_struct_field(
1651 context: &RewriteContext<'_>,
1652 field: &ast::FieldDef,
1654 lhs_max_width: usize,
1655 ) -> Option<String> {
1656 if contains_skip(&field.attrs) {
1657 return Some(context.snippet(field.span()).to_owned());
1660 let type_annotation_spacing = type_annotation_spacing(context.config);
1661 let prefix = rewrite_struct_field_prefix(context, field)?;
1663 let attrs_str = field.attrs.rewrite(context, shape)?;
1664 let attrs_extendable = field.ident.is_none() && is_attributes_extendable(&attrs_str);
1665 let missing_span = if field.attrs.is_empty() {
1666 mk_sp(field.span.lo(), field.span.lo())
1668 mk_sp(field.attrs.last().unwrap().span.hi(), field.span.lo())
1670 let mut spacing = String::from(if field.ident.is_some() {
1671 type_annotation_spacing.1
1675 // Try to put everything on a single line.
1676 let attr_prefix = combine_strs_with_missing_comments(
1684 let overhead = trimmed_last_line_width(&attr_prefix);
1685 let lhs_offset = lhs_max_width.saturating_sub(overhead);
1686 for _ in 0..lhs_offset {
1689 // In this extreme case we will be missing a space between an attribute and a field.
1690 if prefix.is_empty() && !attrs_str.is_empty() && attrs_extendable && spacing.is_empty() {
1694 .offset_left(overhead + spacing.len())
1695 .and_then(|ty_shape| field.ty.rewrite(context, ty_shape));
1696 if let Some(ref ty) = orig_ty {
1697 if !ty.contains('\n') {
1698 return Some(attr_prefix + &spacing + ty);
1702 let is_prefix_empty = prefix.is_empty();
1703 // We must use multiline. We are going to put attributes and a field on different lines.
1704 let field_str = rewrite_assign_rhs(context, prefix, &*field.ty, shape)?;
1705 // Remove a leading white-space from `rewrite_assign_rhs()` when rewriting a tuple struct.
1706 let field_str = if is_prefix_empty {
1707 field_str.trim_start()
1711 combine_strs_with_missing_comments(context, &attrs_str, field_str, missing_span, shape, false)
1714 pub(crate) struct StaticParts<'a> {
1716 vis: &'a ast::Visibility,
1717 ident: symbol::Ident,
1719 mutability: ast::Mutability,
1720 expr_opt: Option<&'a ptr::P<ast::Expr>>,
1721 defaultness: Option<ast::Defaultness>,
1725 impl<'a> StaticParts<'a> {
1726 pub(crate) fn from_item(item: &'a ast::Item) -> Self {
1727 let (defaultness, prefix, ty, mutability, expr) = match item.kind {
1728 ast::ItemKind::Static(ref ty, mutability, ref expr) => {
1729 (None, "static", ty, mutability, expr)
1731 ast::ItemKind::Const(defaultness, ref ty, ref expr) => {
1732 (Some(defaultness), "const", ty, ast::Mutability::Not, expr)
1734 _ => unreachable!(),
1742 expr_opt: expr.as_ref(),
1748 pub(crate) fn from_trait_item(ti: &'a ast::AssocItem) -> Self {
1749 let (defaultness, ty, expr_opt) = match ti.kind {
1750 ast::AssocItemKind::Const(defaultness, ref ty, ref expr_opt) => {
1751 (defaultness, ty, expr_opt)
1753 _ => unreachable!(),
1757 vis: &DEFAULT_VISIBILITY,
1760 mutability: ast::Mutability::Not,
1761 expr_opt: expr_opt.as_ref(),
1762 defaultness: Some(defaultness),
1767 pub(crate) fn from_impl_item(ii: &'a ast::AssocItem) -> Self {
1768 let (defaultness, ty, expr) = match ii.kind {
1769 ast::AssocItemKind::Const(defaultness, ref ty, ref expr) => (defaultness, ty, expr),
1770 _ => unreachable!(),
1777 mutability: ast::Mutability::Not,
1778 expr_opt: expr.as_ref(),
1779 defaultness: Some(defaultness),
1786 context: &RewriteContext<'_>,
1787 static_parts: &StaticParts<'_>,
1789 ) -> Option<String> {
1790 let colon = colon_spaces(context.config);
1791 let mut prefix = format!(
1793 format_visibility(context, static_parts.vis),
1794 static_parts.defaultness.map_or("", format_defaultness),
1795 static_parts.prefix,
1796 format_mutability(static_parts.mutability),
1797 rewrite_ident(context, static_parts.ident),
1802 Shape::indented(offset.block_only(), context.config).offset_left(prefix.len() + 2)?;
1803 let ty_str = match static_parts.ty.rewrite(context, ty_shape) {
1804 Some(ty_str) => ty_str,
1806 if prefix.ends_with(' ') {
1809 let nested_indent = offset.block_indent(context.config);
1810 let nested_shape = Shape::indented(nested_indent, context.config);
1811 let ty_str = static_parts.ty.rewrite(context, nested_shape)?;
1814 nested_indent.to_string_with_newline(context.config),
1820 if let Some(expr) = static_parts.expr_opt {
1821 let comments_lo = context.snippet_provider.span_after(static_parts.span, "=");
1822 let expr_lo = expr.span.lo();
1823 let comments_span = mk_sp(comments_lo, expr_lo);
1825 let lhs = format!("{}{} =", prefix, ty_str);
1828 let remaining_width = context.budget(offset.block_indent + 1);
1829 rewrite_assign_rhs_with_comments(
1833 Shape::legacy(remaining_width, offset.block_only()),
1834 RhsTactics::Default,
1838 .and_then(|res| recover_comment_removed(res, static_parts.span, context))
1839 .map(|s| if s.ends_with(';') { s } else { s + ";" })
1841 Some(format!("{}{};", prefix, ty_str))
1845 pub(crate) fn rewrite_type_alias(
1846 ident: symbol::Ident,
1847 ty_opt: Option<&ptr::P<ast::Ty>>,
1848 generics: &ast::Generics,
1849 generic_bounds_opt: Option<&ast::GenericBounds>,
1850 context: &RewriteContext<'_>,
1852 vis: &ast::Visibility,
1854 ) -> Option<String> {
1867 struct OpaqueType<'a> {
1868 bounds: &'a ast::GenericBounds,
1871 impl<'a> Rewrite for OpaqueType<'a> {
1872 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
1873 let shape = shape.offset_left(5)?; // `impl `
1875 .rewrite(context, shape)
1876 .map(|s| format!("impl {}", s))
1880 pub(crate) fn rewrite_opaque_impl_type(
1881 context: &RewriteContext<'_>,
1882 ident: symbol::Ident,
1883 generics: &ast::Generics,
1884 generic_bounds: &ast::GenericBounds,
1886 ) -> Option<String> {
1887 let ident_str = rewrite_ident(context, ident);
1889 let generics_shape = Shape::indented(indent, context.config).offset_left(5)?;
1890 let generics_str = rewrite_generics(context, ident_str, generics, generics_shape)?;
1891 let prefix = format!("type {} =", generics_str);
1892 let rhs = OpaqueType {
1893 bounds: generic_bounds,
1900 Shape::indented(indent, context.config).sub_width(1)?,
1905 pub(crate) fn rewrite_associated_impl_type(
1906 ident: symbol::Ident,
1907 vis: &ast::Visibility,
1908 defaultness: ast::Defaultness,
1909 ty_opt: Option<&ptr::P<ast::Ty>>,
1910 generics: &ast::Generics,
1911 context: &RewriteContext<'_>,
1914 ) -> Option<String> {
1915 let result = rewrite_type_alias(ident, ty_opt, generics, None, context, indent, vis, span)?;
1918 ast::Defaultness::Default(..) => Some(format!("default {}", result)),
1923 impl Rewrite for ast::FnRetTy {
1924 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
1926 ast::FnRetTy::Default(_) => Some(String::new()),
1927 ast::FnRetTy::Ty(ref ty) => {
1928 if context.config.version() == Version::One
1929 || context.config.indent_style() == IndentStyle::Visual
1931 let inner_width = shape.width.checked_sub(3)?;
1933 .rewrite(context, Shape::legacy(inner_width, shape.indent + 3))
1934 .map(|r| format!("-> {}", r));
1937 ty.rewrite(context, shape.offset_left(3)?)
1938 .map(|s| format!("-> {}", s))
1944 fn is_empty_infer(ty: &ast::Ty, pat_span: Span) -> bool {
1946 ast::TyKind::Infer => ty.span.hi() == pat_span.hi(),
1951 /// Recover any missing comments between the param and the type.
1955 /// A 2-len tuple with the comment before the colon in first position, and the comment after the
1956 /// colon in second position.
1957 fn get_missing_param_comments(
1958 context: &RewriteContext<'_>,
1962 ) -> (String, String) {
1963 let missing_comment_span = mk_sp(pat_span.hi(), ty_span.lo());
1965 let span_before_colon = {
1966 let missing_comment_span_hi = context
1968 .span_before(missing_comment_span, ":");
1969 mk_sp(pat_span.hi(), missing_comment_span_hi)
1971 let span_after_colon = {
1972 let missing_comment_span_lo = context
1974 .span_after(missing_comment_span, ":");
1975 mk_sp(missing_comment_span_lo, ty_span.lo())
1978 let comment_before_colon = rewrite_missing_comment(span_before_colon, shape, context)
1979 .filter(|comment| !comment.is_empty())
1980 .map_or(String::new(), |comment| format!(" {}", comment));
1981 let comment_after_colon = rewrite_missing_comment(span_after_colon, shape, context)
1982 .filter(|comment| !comment.is_empty())
1983 .map_or(String::new(), |comment| format!("{} ", comment));
1984 (comment_before_colon, comment_after_colon)
1987 impl Rewrite for ast::Param {
1988 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
1989 let param_attrs_result = self
1991 .rewrite(context, Shape::legacy(shape.width, shape.indent))?;
1992 let (span, has_multiple_attr_lines) = if !self.attrs.is_empty() {
1993 let num_attrs = self.attrs.len();
1995 mk_sp(self.attrs[num_attrs - 1].span.hi(), self.pat.span.lo()),
1996 param_attrs_result.contains("\n"),
1999 (mk_sp(self.span.lo(), self.span.lo()), false)
2002 if let Some(ref explicit_self) = self.to_self() {
2003 rewrite_explicit_self(
2006 ¶m_attrs_result,
2009 has_multiple_attr_lines,
2011 } else if is_named_param(self) {
2012 let mut result = combine_strs_with_missing_comments(
2014 ¶m_attrs_result,
2017 .rewrite(context, Shape::legacy(shape.width, shape.indent))?,
2020 !has_multiple_attr_lines,
2023 if !is_empty_infer(&*self.ty, self.pat.span) {
2024 let (before_comment, after_comment) =
2025 get_missing_param_comments(context, self.pat.span, self.ty.span, shape);
2026 result.push_str(&before_comment);
2027 result.push_str(colon_spaces(context.config));
2028 result.push_str(&after_comment);
2029 let overhead = last_line_width(&result);
2030 let max_width = shape.width.checked_sub(overhead)?;
2033 .rewrite(context, Shape::legacy(max_width, shape.indent))?;
2034 result.push_str(&ty_str);
2039 self.ty.rewrite(context, shape)
2044 fn rewrite_explicit_self(
2045 context: &RewriteContext<'_>,
2046 explicit_self: &ast::ExplicitSelf,
2050 has_multiple_attr_lines: bool,
2051 ) -> Option<String> {
2052 match explicit_self.node {
2053 ast::SelfKind::Region(lt, m) => {
2054 let mut_str = format_mutability(m);
2057 let lifetime_str = l.rewrite(
2059 Shape::legacy(context.config.max_width(), Indent::empty()),
2061 Some(combine_strs_with_missing_comments(
2064 &format!("&{} {}self", lifetime_str, mut_str),
2067 !has_multiple_attr_lines,
2070 None => Some(combine_strs_with_missing_comments(
2073 &format!("&{}self", mut_str),
2076 !has_multiple_attr_lines,
2080 ast::SelfKind::Explicit(ref ty, mutability) => {
2081 let type_str = ty.rewrite(
2083 Shape::legacy(context.config.max_width(), Indent::empty()),
2086 Some(combine_strs_with_missing_comments(
2089 &format!("{}self: {}", format_mutability(mutability), type_str),
2092 !has_multiple_attr_lines,
2095 ast::SelfKind::Value(mutability) => Some(combine_strs_with_missing_comments(
2098 &format!("{}self", format_mutability(mutability)),
2101 !has_multiple_attr_lines,
2106 pub(crate) fn span_lo_for_param(param: &ast::Param) -> BytePos {
2107 if param.attrs.is_empty() {
2108 if is_named_param(param) {
2114 param.attrs[0].span.lo()
2118 pub(crate) fn span_hi_for_param(context: &RewriteContext<'_>, param: &ast::Param) -> BytePos {
2119 match param.ty.kind {
2120 ast::TyKind::Infer if context.snippet(param.ty.span) == "_" => param.ty.span.hi(),
2121 ast::TyKind::Infer if is_named_param(param) => param.pat.span.hi(),
2122 _ => param.ty.span.hi(),
2126 pub(crate) fn is_named_param(param: &ast::Param) -> bool {
2127 if let ast::PatKind::Ident(_, ident, _) = param.pat.kind {
2128 ident.name != symbol::kw::Empty
2134 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
2135 pub(crate) enum FnBraceStyle {
2141 // Return type is (result, force_new_line_for_brace)
2143 context: &RewriteContext<'_>,
2145 ident: symbol::Ident,
2148 fn_brace_style: FnBraceStyle,
2149 ) -> Option<(String, bool, bool)> {
2150 let mut force_new_line_for_brace = false;
2152 let where_clause = &fn_sig.generics.where_clause;
2154 let mut result = String::with_capacity(1024);
2155 result.push_str(&fn_sig.to_str(context));
2158 result.push_str("fn ");
2161 let overhead = if let FnBraceStyle::SameLine = fn_brace_style {
2168 let used_width = last_line_used_width(&result, indent.width());
2169 let one_line_budget = context.budget(used_width + overhead);
2171 width: one_line_budget,
2175 let fd = fn_sig.decl;
2176 let generics_str = rewrite_generics(
2178 rewrite_ident(context, ident),
2182 result.push_str(&generics_str);
2184 let snuggle_angle_bracket = generics_str
2187 .map_or(false, |l| l.trim_start().len() == 1);
2189 // Note that the width and indent don't really matter, we'll re-layout the
2190 // return type later anyway.
2193 .rewrite(context, Shape::indented(indent, context.config))?;
2195 let multi_line_ret_str = ret_str.contains('\n');
2196 let ret_str_len = if multi_line_ret_str { 0 } else { ret_str.len() };
2199 let (one_line_budget, multi_line_budget, mut param_indent) = compute_budgets_for_params(
2209 "rewrite_fn_base: one_line_budget: {}, multi_line_budget: {}, param_indent: {:?}",
2210 one_line_budget, multi_line_budget, param_indent
2214 // Check if vertical layout was forced.
2215 if one_line_budget == 0
2216 && !snuggle_angle_bracket
2217 && context.config.indent_style() == IndentStyle::Visual
2219 result.push_str(¶m_indent.to_string_with_newline(context.config));
2222 // Skip `pub(crate)`.
2223 let lo_after_visibility = get_bytepos_after_visibility(&fn_sig.visibility, span);
2224 // A conservative estimation, the goal is to be over all parens in generics
2225 let params_start = fn_sig
2229 .map_or(lo_after_visibility, |param| param.span().hi());
2230 let params_end = if fd.inputs.is_empty() {
2233 .span_after(mk_sp(params_start, span.hi()), ")")
2235 let last_span = mk_sp(fd.inputs[fd.inputs.len() - 1].span().hi(), span.hi());
2236 context.snippet_provider.span_after(last_span, ")")
2238 let params_span = mk_sp(
2241 .span_after(mk_sp(params_start, span.hi()), "("),
2244 let param_str = rewrite_params(
2255 let put_params_in_block = match context.config.indent_style() {
2256 IndentStyle::Block => param_str.contains('\n') || param_str.len() > one_line_budget,
2258 } && !fd.inputs.is_empty();
2260 let mut params_last_line_contains_comment = false;
2261 let mut no_params_and_over_max_width = false;
2263 if put_params_in_block {
2264 param_indent = indent.block_indent(context.config);
2265 result.push_str(¶m_indent.to_string_with_newline(context.config));
2266 result.push_str(¶m_str);
2267 result.push_str(&indent.to_string_with_newline(context.config));
2270 result.push_str(¶m_str);
2271 let used_width = last_line_used_width(&result, indent.width()) + first_line_width(&ret_str);
2272 // Put the closing brace on the next line if it overflows the max width.
2274 let closing_paren_overflow_max_width =
2275 fd.inputs.is_empty() && used_width + 1 > context.config.max_width();
2276 // If the last line of params contains comment, we cannot put the closing paren
2277 // on the same line.
2278 params_last_line_contains_comment = param_str
2281 .map_or(false, |last_line| last_line.contains("//"));
2283 if context.config.version() == Version::Two {
2284 if closing_paren_overflow_max_width {
2286 result.push_str(&indent.to_string_with_newline(context.config));
2287 no_params_and_over_max_width = true;
2288 } else if params_last_line_contains_comment {
2289 result.push_str(&indent.to_string_with_newline(context.config));
2291 no_params_and_over_max_width = true;
2296 if closing_paren_overflow_max_width || params_last_line_contains_comment {
2297 result.push_str(&indent.to_string_with_newline(context.config));
2304 if let ast::FnRetTy::Ty(..) = fd.output {
2305 let ret_should_indent = match context.config.indent_style() {
2306 // If our params are block layout then we surely must have space.
2307 IndentStyle::Block if put_params_in_block || fd.inputs.is_empty() => false,
2308 _ if params_last_line_contains_comment => false,
2309 _ if result.contains('\n') || multi_line_ret_str => true,
2311 // If the return type would push over the max width, then put the return type on
2312 // a new line. With the +1 for the signature length an additional space between
2313 // the closing parenthesis of the param and the arrow '->' is considered.
2314 let mut sig_length = result.len() + indent.width() + ret_str_len + 1;
2316 // If there is no where-clause, take into account the space after the return type
2318 if where_clause.predicates.is_empty() {
2322 sig_length > context.config.max_width()
2325 let ret_shape = if ret_should_indent {
2326 if context.config.version() == Version::One
2327 || context.config.indent_style() == IndentStyle::Visual
2329 let indent = if param_str.is_empty() {
2330 // Aligning with non-existent params looks silly.
2331 force_new_line_for_brace = true;
2334 // FIXME: we might want to check that using the param indent
2335 // doesn't blow our budget, and if it does, then fallback to
2336 // the where-clause indent.
2340 result.push_str(&indent.to_string_with_newline(context.config));
2341 Shape::indented(indent, context.config)
2343 let mut ret_shape = Shape::indented(indent, context.config);
2344 if param_str.is_empty() {
2345 // Aligning with non-existent params looks silly.
2346 force_new_line_for_brace = true;
2347 ret_shape = if context.use_block_indent() {
2348 ret_shape.offset_left(4).unwrap_or(ret_shape)
2350 ret_shape.indent = ret_shape.indent + 4;
2355 result.push_str(&ret_shape.indent.to_string_with_newline(context.config));
2359 if context.config.version() == Version::Two {
2360 if !param_str.is_empty() || !no_params_and_over_max_width {
2367 let ret_shape = Shape::indented(indent, context.config);
2369 .offset_left(last_line_width(&result))
2370 .unwrap_or(ret_shape)
2373 if multi_line_ret_str || ret_should_indent {
2374 // Now that we know the proper indent and width, we need to
2375 // re-layout the return type.
2376 let ret_str = fd.output.rewrite(context, ret_shape)?;
2377 result.push_str(&ret_str);
2379 result.push_str(&ret_str);
2382 // Comment between return type and the end of the decl.
2383 let snippet_lo = fd.output.span().hi();
2384 if where_clause.predicates.is_empty() {
2385 let snippet_hi = span.hi();
2386 let snippet = context.snippet(mk_sp(snippet_lo, snippet_hi));
2387 // Try to preserve the layout of the original snippet.
2388 let original_starts_with_newline = snippet
2390 .map_or(false, |i| starts_with_newline(&snippet[i..]));
2391 let original_ends_with_newline = snippet
2392 .rfind(|c| c != ' ')
2393 .map_or(false, |i| snippet[i..].ends_with('\n'));
2394 let snippet = snippet.trim();
2395 if !snippet.is_empty() {
2396 result.push(if original_starts_with_newline {
2401 result.push_str(snippet);
2402 if original_ends_with_newline {
2403 force_new_line_for_brace = true;
2409 let pos_before_where = match fd.output {
2410 ast::FnRetTy::Default(..) => params_span.hi(),
2411 ast::FnRetTy::Ty(ref ty) => ty.span.hi(),
2414 let is_params_multi_lined = param_str.contains('\n');
2416 let space = if put_params_in_block && ret_str.is_empty() {
2417 WhereClauseSpace::Space
2419 WhereClauseSpace::Newline
2421 let mut option = WhereClauseOption::new(fn_brace_style == FnBraceStyle::None, space);
2422 if is_params_multi_lined {
2423 option.veto_single_line();
2425 let where_clause_str = rewrite_where_clause(
2428 context.config.brace_style(),
2429 Shape::indented(indent, context.config),
2436 // If there are neither where-clause nor return type, we may be missing comments between
2438 if where_clause_str.is_empty() {
2439 if let ast::FnRetTy::Default(ret_span) = fd.output {
2440 match recover_missing_comment_in_span(
2441 mk_sp(params_span.hi(), ret_span.hi()),
2444 last_line_width(&result),
2446 Some(ref missing_comment) if !missing_comment.is_empty() => {
2447 result.push_str(missing_comment);
2448 force_new_line_for_brace = true;
2455 result.push_str(&where_clause_str);
2457 let ends_with_comment = last_line_contains_single_line_comment(&result);
2458 force_new_line_for_brace |= ends_with_comment;
2459 force_new_line_for_brace |=
2460 is_params_multi_lined && context.config.where_single_line() && !where_clause_str.is_empty();
2461 Some((result, ends_with_comment, force_new_line_for_brace))
2464 /// Kind of spaces to put before `where`.
2465 #[derive(Copy, Clone)]
2466 enum WhereClauseSpace {
2475 #[derive(Copy, Clone)]
2476 struct WhereClauseOption {
2477 suppress_comma: bool, // Force no trailing comma
2478 snuggle: WhereClauseSpace,
2479 allow_single_line: bool, // Try single line where-clause instead of vertical layout
2480 veto_single_line: bool, // Disallow a single-line where-clause.
2483 impl WhereClauseOption {
2484 fn new(suppress_comma: bool, snuggle: WhereClauseSpace) -> WhereClauseOption {
2488 allow_single_line: false,
2489 veto_single_line: false,
2493 fn snuggled(current: &str) -> WhereClauseOption {
2495 suppress_comma: false,
2496 snuggle: if last_line_width(current) == 1 {
2497 WhereClauseSpace::Space
2499 WhereClauseSpace::Newline
2501 allow_single_line: false,
2502 veto_single_line: false,
2506 fn suppress_comma(&mut self) {
2507 self.suppress_comma = true
2510 fn allow_single_line(&mut self) {
2511 self.allow_single_line = true
2514 fn snuggle(&mut self) {
2515 self.snuggle = WhereClauseSpace::Space
2518 fn veto_single_line(&mut self) {
2519 self.veto_single_line = true;
2524 context: &RewriteContext<'_>,
2525 params: &[ast::Param],
2526 one_line_budget: usize,
2527 multi_line_budget: usize,
2529 param_indent: Indent,
2532 ) -> Option<String> {
2533 if params.is_empty() {
2534 let comment = context
2538 span.hi() - BytePos(1),
2541 return Some(comment.to_owned());
2543 let param_items: Vec<_> = itemize_list(
2544 context.snippet_provider,
2548 |param| span_lo_for_param(param),
2549 |param| param.ty.span.hi(),
2552 .rewrite(context, Shape::legacy(multi_line_budget, param_indent))
2553 .or_else(|| Some(context.snippet(param.span()).to_owned()))
2561 let tactic = definitive_tactic(
2566 .to_list_tactic(param_items.len()),
2570 let budget = match tactic {
2571 DefinitiveListTactic::Horizontal => one_line_budget,
2572 _ => multi_line_budget,
2574 let indent = match context.config.indent_style() {
2575 IndentStyle::Block => indent.block_indent(context.config),
2576 IndentStyle::Visual => param_indent,
2578 let trailing_separator = if variadic {
2579 SeparatorTactic::Never
2581 match context.config.indent_style() {
2582 IndentStyle::Block => context.config.trailing_comma(),
2583 IndentStyle::Visual => SeparatorTactic::Never,
2586 let fmt = ListFormatting::new(Shape::legacy(budget, indent), context.config)
2588 .trailing_separator(trailing_separator)
2589 .ends_with_newline(tactic.ends_with_newline(context.config.indent_style()))
2590 .preserve_newline(true);
2591 write_list(¶m_items, &fmt)
2594 fn compute_budgets_for_params(
2595 context: &RewriteContext<'_>,
2599 fn_brace_style: FnBraceStyle,
2600 force_vertical_layout: bool,
2601 ) -> Option<(usize, usize, Indent)> {
2603 "compute_budgets_for_params {} {:?}, {}, {:?}",
2609 // Try keeping everything on the same line.
2610 if !result.contains('\n') && !force_vertical_layout {
2611 // 2 = `()`, 3 = `() `, space is before ret_string.
2612 let overhead = if ret_str_len == 0 { 2 } else { 3 };
2613 let mut used_space = indent.width() + result.len() + ret_str_len + overhead;
2614 match fn_brace_style {
2615 FnBraceStyle::None => used_space += 1, // 1 = `;`
2616 FnBraceStyle::SameLine => used_space += 2, // 2 = `{}`
2617 FnBraceStyle::NextLine => (),
2619 let one_line_budget = context.budget(used_space);
2621 if one_line_budget > 0 {
2623 let (indent, multi_line_budget) = match context.config.indent_style() {
2624 IndentStyle::Block => {
2625 let indent = indent.block_indent(context.config);
2626 (indent, context.budget(indent.width() + 1))
2628 IndentStyle::Visual => {
2629 let indent = indent + result.len() + 1;
2630 let multi_line_overhead = match fn_brace_style {
2631 FnBraceStyle::SameLine => 4,
2634 (indent, context.budget(multi_line_overhead))
2638 return Some((one_line_budget, multi_line_budget, indent));
2642 // Didn't work. we must force vertical layout and put params on a newline.
2643 let new_indent = indent.block_indent(context.config);
2644 let used_space = match context.config.indent_style() {
2646 IndentStyle::Block => new_indent.width() + 1,
2647 // Account for `)` and possibly ` {`.
2648 IndentStyle::Visual => new_indent.width() + if ret_str_len == 0 { 1 } else { 3 },
2650 Some((0, context.budget(used_space), new_indent))
2653 fn newline_for_brace(config: &Config, where_clause: &ast::WhereClause) -> FnBraceStyle {
2654 let predicate_count = where_clause.predicates.len();
2656 if config.where_single_line() && predicate_count == 1 {
2657 return FnBraceStyle::SameLine;
2659 let brace_style = config.brace_style();
2661 let use_next_line = brace_style == BraceStyle::AlwaysNextLine
2662 || (brace_style == BraceStyle::SameLineWhere && predicate_count > 0);
2664 FnBraceStyle::NextLine
2666 FnBraceStyle::SameLine
2670 fn rewrite_generics(
2671 context: &RewriteContext<'_>,
2673 generics: &ast::Generics,
2675 ) -> Option<String> {
2676 // FIXME: convert bounds to where-clauses where they get too big or if
2677 // there is a where-clause at all.
2679 if generics.params.is_empty() {
2680 return Some(ident.to_owned());
2683 let params = generics.params.iter();
2684 overflow::rewrite_with_angle_brackets(context, ident, params, shape, generics.span)
2687 fn generics_shape_from_config(config: &Config, shape: Shape, offset: usize) -> Option<Shape> {
2688 match config.indent_style() {
2689 IndentStyle::Visual => shape.visual_indent(1 + offset).sub_width(offset + 2),
2690 IndentStyle::Block => {
2694 .block_indent(config.tab_spaces())
2695 .with_max_width(config)
2701 fn rewrite_where_clause_rfc_style(
2702 context: &RewriteContext<'_>,
2703 where_clause: &ast::WhereClause,
2706 span_end: Option<BytePos>,
2707 span_end_before_where: BytePos,
2708 where_clause_option: WhereClauseOption,
2709 ) -> Option<String> {
2710 let (where_keyword, allow_single_line) = rewrite_where_keyword(
2714 span_end_before_where,
2715 where_clause_option,
2719 let clause_shape = shape
2721 .with_max_width(context.config)
2722 .block_left(context.config.tab_spaces())?
2724 let force_single_line = context.config.where_single_line()
2725 && where_clause.predicates.len() == 1
2726 && !where_clause_option.veto_single_line;
2728 let preds_str = rewrite_bounds_on_where_clause(
2734 where_clause_option,
2740 if allow_single_line && !preds_str.contains('\n') && 6 + preds_str.len() <= shape.width
2741 || force_single_line
2745 clause_shape.indent.to_string_with_newline(context.config)
2748 Some(format!("{}{}{}", where_keyword, clause_sep, preds_str))
2751 /// Rewrite `where` and comment around it.
2752 fn rewrite_where_keyword(
2753 context: &RewriteContext<'_>,
2754 where_clause: &ast::WhereClause,
2756 span_end_before_where: BytePos,
2757 where_clause_option: WhereClauseOption,
2758 ) -> Option<(String, bool)> {
2759 let block_shape = shape.block().with_max_width(context.config);
2761 let clause_shape = block_shape
2762 .block_left(context.config.tab_spaces())?
2765 let comment_separator = |comment: &str, shape: Shape| {
2766 if comment.is_empty() {
2769 shape.indent.to_string_with_newline(context.config)
2773 let (span_before, span_after) =
2774 missing_span_before_after_where(span_end_before_where, where_clause);
2775 let (comment_before, comment_after) =
2776 rewrite_comments_before_after_where(context, span_before, span_after, shape)?;
2778 let starting_newline = match where_clause_option.snuggle {
2779 WhereClauseSpace::Space if comment_before.is_empty() => Cow::from(" "),
2780 WhereClauseSpace::None => Cow::from(""),
2781 _ => block_shape.indent.to_string_with_newline(context.config),
2784 let newline_before_where = comment_separator(&comment_before, shape);
2785 let newline_after_where = comment_separator(&comment_after, clause_shape);
2786 let result = format!(
2788 starting_newline, comment_before, newline_before_where, newline_after_where, comment_after
2790 let allow_single_line = where_clause_option.allow_single_line
2791 && comment_before.is_empty()
2792 && comment_after.is_empty();
2794 Some((result, allow_single_line))
2797 /// Rewrite bounds on a where clause.
2798 fn rewrite_bounds_on_where_clause(
2799 context: &RewriteContext<'_>,
2800 where_clause: &ast::WhereClause,
2803 span_end: Option<BytePos>,
2804 where_clause_option: WhereClauseOption,
2805 force_single_line: bool,
2806 ) -> Option<String> {
2807 let span_start = where_clause.predicates[0].span().lo();
2808 // If we don't have the start of the next span, then use the end of the
2809 // predicates, but that means we miss comments.
2810 let len = where_clause.predicates.len();
2811 let end_of_preds = where_clause.predicates[len - 1].span().hi();
2812 let span_end = span_end.unwrap_or(end_of_preds);
2813 let items = itemize_list(
2814 context.snippet_provider,
2815 where_clause.predicates.iter(),
2818 |pred| pred.span().lo(),
2819 |pred| pred.span().hi(),
2820 |pred| pred.rewrite(context, shape),
2825 let comma_tactic = if where_clause_option.suppress_comma || force_single_line {
2826 SeparatorTactic::Never
2828 context.config.trailing_comma()
2831 // shape should be vertical only and only if we have `force_single_line` option enabled
2832 // and the number of items of the where-clause is equal to 1
2833 let shape_tactic = if force_single_line {
2834 DefinitiveListTactic::Horizontal
2836 DefinitiveListTactic::Vertical
2839 let fmt = ListFormatting::new(shape, context.config)
2840 .tactic(shape_tactic)
2841 .trailing_separator(comma_tactic)
2842 .preserve_newline(true);
2843 write_list(&items.collect::<Vec<_>>(), &fmt)
2846 fn rewrite_where_clause(
2847 context: &RewriteContext<'_>,
2848 where_clause: &ast::WhereClause,
2849 brace_style: BraceStyle,
2853 span_end: Option<BytePos>,
2854 span_end_before_where: BytePos,
2855 where_clause_option: WhereClauseOption,
2856 ) -> Option<String> {
2857 if where_clause.predicates.is_empty() {
2858 return Some(String::new());
2861 if context.config.indent_style() == IndentStyle::Block {
2862 return rewrite_where_clause_rfc_style(
2868 span_end_before_where,
2869 where_clause_option,
2873 let extra_indent = Indent::new(context.config.tab_spaces(), 0);
2875 let offset = match context.config.indent_style() {
2876 IndentStyle::Block => shape.indent + extra_indent.block_indent(context.config),
2877 // 6 = "where ".len()
2878 IndentStyle::Visual => shape.indent + extra_indent + 6,
2880 // FIXME: if indent_style != Visual, then the budgets below might
2881 // be out by a char or two.
2883 let budget = context.config.max_width() - offset.width();
2884 let span_start = where_clause.predicates[0].span().lo();
2885 // If we don't have the start of the next span, then use the end of the
2886 // predicates, but that means we miss comments.
2887 let len = where_clause.predicates.len();
2888 let end_of_preds = where_clause.predicates[len - 1].span().hi();
2889 let span_end = span_end.unwrap_or(end_of_preds);
2890 let items = itemize_list(
2891 context.snippet_provider,
2892 where_clause.predicates.iter(),
2895 |pred| pred.span().lo(),
2896 |pred| pred.span().hi(),
2897 |pred| pred.rewrite(context, Shape::legacy(budget, offset)),
2902 let item_vec = items.collect::<Vec<_>>();
2903 // FIXME: we don't need to collect here
2904 let tactic = definitive_tactic(&item_vec, ListTactic::Vertical, Separator::Comma, budget);
2906 let mut comma_tactic = context.config.trailing_comma();
2907 // Kind of a hack because we don't usually have trailing commas in where-clauses.
2908 if comma_tactic == SeparatorTactic::Vertical || where_clause_option.suppress_comma {
2909 comma_tactic = SeparatorTactic::Never;
2912 let fmt = ListFormatting::new(Shape::legacy(budget, offset), context.config)
2914 .trailing_separator(comma_tactic)
2915 .ends_with_newline(tactic.ends_with_newline(context.config.indent_style()))
2916 .preserve_newline(true);
2917 let preds_str = write_list(&item_vec, &fmt)?;
2919 let end_length = if terminator == "{" {
2920 // If the brace is on the next line we don't need to count it otherwise it needs two
2923 BraceStyle::AlwaysNextLine | BraceStyle::SameLineWhere => 0,
2924 BraceStyle::PreferSameLine => 2,
2926 } else if terminator == "=" {
2932 || preds_str.contains('\n')
2933 || shape.indent.width() + " where ".len() + preds_str.len() + end_length > shape.width
2937 (shape.indent + extra_indent).to_string(context.config),
2941 Some(format!(" where {}", preds_str))
2945 fn missing_span_before_after_where(
2946 before_item_span_end: BytePos,
2947 where_clause: &ast::WhereClause,
2949 let missing_span_before = mk_sp(before_item_span_end, where_clause.span.lo());
2951 let pos_after_where = where_clause.span.lo() + BytePos(5);
2952 let missing_span_after = mk_sp(pos_after_where, where_clause.predicates[0].span().lo());
2953 (missing_span_before, missing_span_after)
2956 fn rewrite_comments_before_after_where(
2957 context: &RewriteContext<'_>,
2958 span_before_where: Span,
2959 span_after_where: Span,
2961 ) -> Option<(String, String)> {
2962 let before_comment = rewrite_missing_comment(span_before_where, shape, context)?;
2963 let after_comment = rewrite_missing_comment(
2965 shape.block_indent(context.config.tab_spaces()),
2968 Some((before_comment, after_comment))
2972 context: &RewriteContext<'_>,
2974 ident: symbol::Ident,
2975 vis: &ast::Visibility,
2978 let mut result = String::with_capacity(128);
2979 let shape = Shape::indented(offset, context.config);
2981 result.push_str(&format_visibility(context, vis).trim());
2983 // Check for a missing comment between the visibility and the item name.
2984 let after_vis = vis.span.hi();
2985 if let Some(before_item_name) = context
2987 .opt_span_before(mk_sp(vis.span.lo(), ident.span.hi()), item_name.trim())
2989 let missing_span = mk_sp(after_vis, before_item_name);
2990 if let Some(result_with_comment) = combine_strs_with_missing_comments(
2996 /* allow_extend */ true,
2998 result = result_with_comment;
3002 result.push_str(&rewrite_ident(context, ident));
3007 #[derive(PartialEq, Eq, Clone, Copy)]
3015 context: &RewriteContext<'_>,
3016 generics: &ast::Generics,
3017 brace_style: BraceStyle,
3018 brace_pos: BracePos,
3022 ) -> Option<String> {
3023 let shape = Shape::legacy(context.budget(used_width + offset.width()), offset);
3024 let mut result = rewrite_generics(context, "", generics, shape)?;
3026 // If the generics are not parameterized then generics.span.hi() == 0,
3027 // so we use span.lo(), which is the position after `struct Foo`.
3028 let span_end_before_where = if !generics.params.is_empty() {
3033 let (same_line_brace, missed_comments) = if !generics.where_clause.predicates.is_empty() {
3034 let budget = context.budget(last_line_used_width(&result, offset.width()));
3035 let mut option = WhereClauseOption::snuggled(&result);
3036 if brace_pos == BracePos::None {
3037 option.suppress_comma = true;
3039 let where_clause_str = rewrite_where_clause(
3041 &generics.where_clause,
3043 Shape::legacy(budget, offset.block_only()),
3047 span_end_before_where,
3050 result.push_str(&where_clause_str);
3052 brace_pos == BracePos::ForceSameLine || brace_style == BraceStyle::PreferSameLine,
3053 // missed comments are taken care of in #rewrite_where_clause
3058 brace_pos == BracePos::ForceSameLine
3059 || (result.contains('\n') && brace_style == BraceStyle::PreferSameLine
3060 || brace_style != BraceStyle::AlwaysNextLine)
3061 || trimmed_last_line_width(&result) == 1,
3062 rewrite_missing_comment(
3064 span_end_before_where,
3065 if brace_pos == BracePos::None {
3068 context.snippet_provider.span_before(span, "{")
3076 // add missing comments
3077 let missed_line_comments = missed_comments
3078 .filter(|missed_comments| !missed_comments.is_empty())
3079 .map_or(false, |missed_comments| {
3080 let is_block = is_last_comment_block(&missed_comments);
3081 let sep = if is_block { " " } else { "\n" };
3082 result.push_str(sep);
3083 result.push_str(&missed_comments);
3086 if brace_pos == BracePos::None {
3087 return Some(result);
3089 let total_used_width = last_line_used_width(&result, used_width);
3090 let remaining_budget = context.budget(total_used_width);
3091 // If the same line brace if forced, it indicates that we are rewriting an item with empty body,
3092 // and hence we take the closer into account as well for one line budget.
3093 // We assume that the closer has the same length as the opener.
3094 let overhead = if brace_pos == BracePos::ForceSameLine {
3101 let forbid_same_line_brace = missed_line_comments || overhead > remaining_budget;
3102 if !forbid_same_line_brace && same_line_brace {
3106 result.push_str(&offset.block_only().to_string(context.config));
3113 impl Rewrite for ast::ForeignItem {
3114 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
3115 let attrs_str = self.attrs.rewrite(context, shape)?;
3116 // Drop semicolon or it will be interpreted as comment.
3117 // FIXME: this may be a faulty span from libsyntax.
3118 let span = mk_sp(self.span.lo(), self.span.hi() - BytePos(1));
3120 let item_str = match self.kind {
3121 ast::ForeignItemKind::Fn(ref fn_kind) => {
3122 let ast::FnKind(defaultness, ref fn_sig, ref generics, ref block) = **fn_kind;
3123 if let Some(ref body) = block {
3124 let mut visitor = FmtVisitor::from_context(context);
3125 visitor.block_indent = shape.indent;
3126 visitor.last_pos = self.span.lo();
3127 let inner_attrs = inner_attributes(&self.attrs);
3128 let fn_ctxt = visit::FnCtxt::Foreign;
3130 visit::FnKind::Fn(fn_ctxt, self.ident, &fn_sig, &self.vis, Some(body)),
3137 Some(visitor.buffer.to_owned())
3143 &FnSig::from_method_sig(&fn_sig, generics, self.vis.clone()),
3147 .map(|(s, _, _)| format!("{};", s))
3150 ast::ForeignItemKind::Static(ref ty, mutability, _) => {
3151 // FIXME(#21): we're dropping potential comments in between the
3152 // function kw here.
3153 let vis = format_visibility(context, &self.vis);
3154 let mut_str = format_mutability(mutability);
3155 let prefix = format!(
3159 rewrite_ident(context, self.ident)
3162 rewrite_assign_rhs(context, prefix, &**ty, shape.sub_width(1)?).map(|s| s + ";")
3164 ast::ForeignItemKind::TyAlias(ref ty_alias_kind) => {
3165 let ast::TyAliasKind(_, ref generics, ref generic_bounds, ref type_default) =
3169 type_default.as_ref(),
3171 Some(generic_bounds),
3178 ast::ForeignItemKind::MacCall(ref mac) => {
3179 rewrite_macro(mac, None, context, shape, MacroPosition::Item)
3183 let missing_span = if self.attrs.is_empty() {
3184 mk_sp(self.span.lo(), self.span.lo())
3186 mk_sp(self.attrs[self.attrs.len() - 1].span.hi(), self.span.lo())
3188 combine_strs_with_missing_comments(
3199 /// Rewrite the attributes of an item.
3201 context: &RewriteContext<'_>,
3205 ) -> Option<String> {
3206 let attrs = filter_inline_attrs(&item.attrs, item.span());
3207 let attrs_str = attrs.rewrite(context, shape)?;
3209 let missed_span = if attrs.is_empty() {
3210 mk_sp(item.span.lo(), item.span.lo())
3212 mk_sp(attrs[attrs.len() - 1].span.hi(), item.span.lo())
3215 let allow_extend = if attrs.len() == 1 {
3216 let line_len = attrs_str.len() + 1 + item_str.len();
3217 !attrs.first().unwrap().is_doc_comment()
3218 && context.config.inline_attribute_width() >= line_len
3223 combine_strs_with_missing_comments(
3233 /// Rewrite an inline mod.
3234 /// The given shape is used to format the mod's attributes.
3235 pub(crate) fn rewrite_mod(
3236 context: &RewriteContext<'_>,
3239 ) -> Option<String> {
3240 let mut result = String::with_capacity(32);
3241 result.push_str(&*format_visibility(context, &item.vis));
3242 result.push_str("mod ");
3243 result.push_str(rewrite_ident(context, item.ident));
3245 rewrite_attrs(context, item, &result, attrs_shape)
3248 /// Rewrite `extern crate foo;`.
3249 /// The given shape is used to format the extern crate's attributes.
3250 pub(crate) fn rewrite_extern_crate(
3251 context: &RewriteContext<'_>,
3254 ) -> Option<String> {
3255 assert!(is_extern_crate(item));
3256 let new_str = context.snippet(item.span);
3257 let item_str = if contains_comment(new_str) {
3260 let no_whitespace = &new_str.split_whitespace().collect::<Vec<&str>>().join(" ");
3261 String::from(&*Regex::new(r"\s;").unwrap().replace(no_whitespace, ";"))
3263 rewrite_attrs(context, item, &item_str, attrs_shape)
3266 /// Returns `true` for `mod foo;`, false for `mod foo { .. }`.
3267 pub(crate) fn is_mod_decl(item: &ast::Item) -> bool {
3269 ast::ItemKind::Mod(_, ast::ModKind::Loaded(_, ast::Inline::Yes, _)) => false,
3274 pub(crate) fn is_use_item(item: &ast::Item) -> bool {
3276 ast::ItemKind::Use(_) => true,
3281 pub(crate) fn is_extern_crate(item: &ast::Item) -> bool {
3283 ast::ItemKind::ExternCrate(..) => true,