1 // Formatting top-level items - functions, structs, enums, traits, impls.
4 use std::cmp::{max, min, Ordering};
7 use rustc_target::spec::abi;
8 use syntax::source_map::{self, BytePos, Span};
10 use syntax::{ast, ptr, symbol};
12 use crate::attr::filter_inline_attrs;
14 combine_strs_with_missing_comments, contains_comment, is_last_comment_block,
15 recover_comment_removed, recover_missing_comment_in_span, rewrite_missing_comment,
18 use crate::config::lists::*;
19 use crate::config::{BraceStyle, Config, IndentStyle, Version};
21 is_empty_block, is_simple_block_stmt, rewrite_assign_rhs, rewrite_assign_rhs_with, 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;
35 const DEFAULT_VISIBILITY: ast::Visibility = source_map::Spanned {
36 node: ast::VisibilityKind::Inherited,
37 span: source_map::DUMMY_SP,
40 fn type_annotation_separator(config: &Config) -> &str {
44 // Statements of the form
45 // let pat: ty = init;
46 impl Rewrite for ast::Local {
47 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
49 "Local::rewrite {:?} {} {:?}",
50 self, shape.width, shape.indent
53 skip_out_of_file_lines_range!(context, self.span);
55 if contains_skip(&self.attrs) {
59 let attrs_str = self.attrs.rewrite(context, shape)?;
60 let mut result = if attrs_str.is_empty() {
63 combine_strs_with_missing_comments(
68 self.attrs.last().map(|a| a.span.hi()).unwrap(),
77 let pat_shape = shape.offset_left(4)?;
79 let pat_shape = pat_shape.sub_width(1)?;
80 let pat_str = self.pat.rewrite(context, pat_shape)?;
81 result.push_str(&pat_str);
83 // String that is placed within the assignment pattern and expression.
85 let mut infix = String::with_capacity(32);
87 if let Some(ref ty) = self.ty {
88 let separator = type_annotation_separator(context.config);
89 let ty_shape = if pat_str.contains('\n') {
90 shape.with_max_width(context.config)
94 .offset_left(last_line_width(&result) + separator.len())?
98 let rewrite = ty.rewrite(context, ty_shape)?;
100 infix.push_str(separator);
101 infix.push_str(&rewrite);
104 if self.init.is_some() {
105 infix.push_str(" =");
111 result.push_str(&infix);
113 if let Some(ref ex) = self.init {
114 // 1 = trailing semicolon;
115 let nested_shape = shape.sub_width(1)?;
117 result = rewrite_assign_rhs(context, result, &**ex, nested_shape)?;
125 // FIXME convert to using rewrite style rather than visitor
126 // FIXME format modules in this style
129 keyword: &'static str,
130 abi: Cow<'static, str>,
131 vis: Option<&'a ast::Visibility>,
132 body: Vec<BodyElement<'a>>,
137 fn from_foreign_mod(fm: &'a ast::ForeignMod, span: Span, config: &Config) -> Item<'a> {
140 abi: format_abi(fm.abi, config.force_explicit_abi(), true),
145 .map(|i| BodyElement::ForeignItem(i))
152 enum BodyElement<'a> {
153 // Stmt(&'a ast::Stmt),
154 // Field(&'a ast::Field),
155 // Variant(&'a ast::Variant),
156 // Item(&'a ast::Item),
157 ForeignItem(&'a ast::ForeignItem),
160 /// Represents a fn's signature.
161 pub(crate) struct FnSig<'a> {
162 decl: &'a ast::FnDecl,
163 generics: &'a ast::Generics,
165 is_async: Cow<'a, ast::IsAsync>,
166 constness: ast::Constness,
167 defaultness: ast::Defaultness,
168 unsafety: ast::Unsafety,
169 visibility: ast::Visibility,
174 decl: &'a ast::FnDecl,
175 generics: &'a ast::Generics,
176 vis: ast::Visibility,
182 is_async: Cow::Owned(ast::IsAsync::NotAsync),
183 constness: ast::Constness::NotConst,
184 defaultness: ast::Defaultness::Final,
185 unsafety: ast::Unsafety::Normal,
190 pub(crate) fn from_method_sig(
191 method_sig: &'a ast::MethodSig,
192 generics: &'a ast::Generics,
195 unsafety: method_sig.header.unsafety,
196 is_async: Cow::Borrowed(&method_sig.header.asyncness.node),
197 constness: method_sig.header.constness.node,
198 defaultness: ast::Defaultness::Final,
199 abi: method_sig.header.abi,
200 decl: &*method_sig.decl,
202 visibility: DEFAULT_VISIBILITY,
206 pub(crate) fn from_fn_kind(
207 fn_kind: &'a visit::FnKind<'_>,
208 generics: &'a ast::Generics,
209 decl: &'a ast::FnDecl,
210 defaultness: ast::Defaultness,
213 visit::FnKind::ItemFn(_, fn_header, visibility, _) => FnSig {
217 constness: fn_header.constness.node,
218 is_async: Cow::Borrowed(&fn_header.asyncness.node),
220 unsafety: fn_header.unsafety,
221 visibility: visibility.clone(),
223 visit::FnKind::Method(_, method_sig, vis, _) => {
224 let mut fn_sig = FnSig::from_method_sig(method_sig, generics);
225 fn_sig.defaultness = defaultness;
226 if let Some(vis) = vis {
227 fn_sig.visibility = vis.clone();
235 fn to_str(&self, context: &RewriteContext<'_>) -> String {
236 let mut result = String::with_capacity(128);
237 // Vis defaultness constness unsafety abi.
238 result.push_str(&*format_visibility(context, &self.visibility));
239 result.push_str(format_defaultness(self.defaultness));
240 result.push_str(format_constness(self.constness));
241 result.push_str(format_async(&self.is_async));
242 result.push_str(format_unsafety(self.unsafety));
243 result.push_str(&format_abi(
245 context.config.force_explicit_abi(),
252 impl<'a> FmtVisitor<'a> {
253 fn format_item(&mut self, item: &Item<'_>) {
254 self.buffer.push_str(&item.abi);
256 let snippet = self.snippet(item.span);
257 let brace_pos = snippet.find_uncommented("{").unwrap();
260 if !item.body.is_empty() || contains_comment(&snippet[brace_pos..]) {
261 // FIXME: this skips comments between the extern keyword and the opening
263 self.last_pos = item.span.lo() + BytePos(brace_pos as u32 + 1);
264 self.block_indent = self.block_indent.block_indent(self.config);
266 if item.body.is_empty() {
267 self.format_missing_no_indent(item.span.hi() - BytePos(1));
268 self.block_indent = self.block_indent.block_unindent(self.config);
269 let indent_str = self.block_indent.to_string(self.config);
270 self.push_str(&indent_str);
272 for item in &item.body {
273 self.format_body_element(item);
276 self.block_indent = self.block_indent.block_unindent(self.config);
277 self.format_missing_with_indent(item.span.hi() - BytePos(1));
282 self.last_pos = item.span.hi();
285 fn format_body_element(&mut self, element: &BodyElement<'_>) {
287 BodyElement::ForeignItem(item) => self.format_foreign_item(item),
291 pub(crate) fn format_foreign_mod(&mut self, fm: &ast::ForeignMod, span: Span) {
292 let item = Item::from_foreign_mod(fm, span, self.config);
293 self.format_item(&item);
296 fn format_foreign_item(&mut self, item: &ast::ForeignItem) {
297 let rewrite = item.rewrite(&self.get_context(), self.shape());
298 self.push_rewrite(item.span(), rewrite);
299 self.last_pos = item.span.hi();
302 pub(crate) fn rewrite_fn_before_block(
308 ) -> Option<(String, FnBraceStyle)> {
309 let context = self.get_context();
311 let mut fn_brace_style = newline_for_brace(self.config, &fn_sig.generics.where_clause);
312 let (result, force_newline_brace) =
313 rewrite_fn_base(&context, indent, ident, fn_sig, span, fn_brace_style)?;
316 if self.config.brace_style() == BraceStyle::AlwaysNextLine
317 || force_newline_brace
318 || last_line_width(&result) + 2 > self.shape().width
320 fn_brace_style = FnBraceStyle::NextLine
323 Some((result, fn_brace_style))
326 pub(crate) fn rewrite_required_fn(
330 sig: &ast::MethodSig,
331 generics: &ast::Generics,
333 ) -> Option<String> {
334 // Drop semicolon or it will be interpreted as comment.
335 let span = mk_sp(span.lo(), span.hi() - BytePos(1));
336 let context = self.get_context();
338 let (mut result, _) = rewrite_fn_base(
342 &FnSig::from_method_sig(sig, generics),
347 // Re-attach semicolon
353 pub(crate) fn single_line_fn(
357 inner_attrs: Option<&[ast::Attribute]>,
358 ) -> Option<String> {
359 if fn_str.contains('\n') || inner_attrs.map_or(false, |a| !a.is_empty()) {
363 let source_map = self.get_context().source_map;
365 if self.config.empty_item_single_line()
366 && is_empty_block(block, None, source_map)
367 && self.block_indent.width() + fn_str.len() + 3 <= self.config.max_width()
368 && !last_line_contains_single_line_comment(fn_str)
370 return Some(format!("{} {{}}", fn_str));
373 if !self.config.fn_single_line() || !is_simple_block_stmt(block, None, source_map) {
377 let res = Stmt::from_ast_node(block.stmts.first()?, true)
378 .rewrite(&self.get_context(), self.shape())?;
380 let width = self.block_indent.width() + fn_str.len() + res.len() + 5;
381 if !res.contains('\n') && width <= self.config.max_width() {
382 Some(format!("{} {{ {} }}", fn_str, res))
388 pub(crate) fn visit_static(&mut self, static_parts: &StaticParts<'_>) {
389 let rewrite = rewrite_static(&self.get_context(), static_parts, self.block_indent);
390 self.push_rewrite(static_parts.span, rewrite);
393 pub(crate) fn visit_struct(&mut self, struct_parts: &StructParts<'_>) {
394 let is_tuple = match struct_parts.def {
395 ast::VariantData::Tuple(..) => true,
398 let rewrite = format_struct(&self.get_context(), struct_parts, self.block_indent, None)
399 .map(|s| if is_tuple { s + ";" } else { s });
400 self.push_rewrite(struct_parts.span, rewrite);
403 pub(crate) fn visit_enum(
406 vis: &ast::Visibility,
407 enum_def: &ast::EnumDef,
408 generics: &ast::Generics,
411 let enum_header = format_header(&self.get_context(), "enum ", ident, vis);
412 self.push_str(&enum_header);
414 let enum_snippet = self.snippet(span);
415 let brace_pos = enum_snippet.find_uncommented("{").unwrap();
416 let body_start = span.lo() + BytePos(brace_pos as u32 + 1);
417 let generics_str = format_generics(
420 self.config.brace_style(),
421 if enum_def.variants.is_empty() {
422 BracePos::ForceSameLine
427 // make a span that starts right after `enum Foo`
428 mk_sp(ident.span.hi(), body_start),
429 last_line_width(&enum_header),
432 self.push_str(&generics_str);
434 self.last_pos = body_start;
436 match self.format_variant_list(enum_def, body_start, span.hi()) {
437 Some(ref s) if enum_def.variants.is_empty() => self.push_str(s),
439 self.push_rewrite(mk_sp(body_start, span.hi()), rw);
440 self.block_indent = self.block_indent.block_unindent(self.config);
445 // Format the body of an enum definition
446 fn format_variant_list(
448 enum_def: &ast::EnumDef,
451 ) -> Option<String> {
452 if enum_def.variants.is_empty() {
453 let mut buffer = String::with_capacity(128);
455 let span = mk_sp(body_lo, body_hi - BytePos(1));
456 format_empty_struct_or_tuple(
466 let mut result = String::with_capacity(1024);
467 let original_offset = self.block_indent;
468 self.block_indent = self.block_indent.block_indent(self.config);
470 // If enum variants have discriminants, try to vertically align those,
471 // provided the discrims are not shifted too much to the right
472 let align_threshold: usize = self.config.enum_discrim_align_threshold();
473 let discr_ident_lens: Vec<usize> = enum_def
476 .filter(|var| var.disr_expr.is_some())
477 .map(|var| rewrite_ident(&self.get_context(), var.ident).len())
479 // cut the list at the point of longest discrim shorter than the threshold
480 // All of the discrims under the threshold will get padded, and all above - left as is.
481 let pad_discrim_ident_to = *discr_ident_lens
483 .filter(|&l| *l <= align_threshold)
487 let itemize_list_with = |one_line_width: usize| {
489 self.snippet_provider,
490 enum_def.variants.iter(),
494 if !f.attrs.is_empty() {
501 |f| self.format_variant(f, one_line_width, pad_discrim_ident_to),
508 let mut items: Vec<_> =
509 itemize_list_with(self.config.width_heuristics().struct_variant_width);
510 // If one of the variants use multiple lines, use multi-lined formatting for all variants.
511 let has_multiline_variant = items.iter().any(|item| item.inner_as_ref().contains('\n'));
512 let has_single_line_variant = items.iter().any(|item| !item.inner_as_ref().contains('\n'));
513 if has_multiline_variant && has_single_line_variant {
514 items = itemize_list_with(0);
517 let shape = self.shape().sub_width(2)?;
518 let fmt = ListFormatting::new(shape, self.config)
519 .trailing_separator(self.config.trailing_comma())
520 .preserve_newline(true);
522 let list = write_list(&items, &fmt)?;
523 result.push_str(&list);
524 result.push_str(&original_offset.to_string_with_newline(self.config));
529 // Variant of an enum.
532 field: &ast::Variant,
533 one_line_width: usize,
534 pad_discrim_ident_to: usize,
535 ) -> Option<String> {
536 if contains_skip(&field.attrs) {
537 let lo = field.attrs[0].span.lo();
538 let span = mk_sp(lo, field.span.hi());
539 return Some(self.snippet(span).to_owned());
542 let context = self.get_context();
544 let shape = self.shape().sub_width(1)?;
545 let attrs_str = field.attrs.rewrite(&context, shape)?;
549 .map_or(field.span.lo(), |attr| attr.span.hi());
550 let span = mk_sp(lo, field.span.lo());
552 let variant_body = match field.data {
553 ast::VariantData::Tuple(..) | ast::VariantData::Struct(..) => format_struct(
555 &StructParts::from_variant(field),
557 Some(one_line_width),
559 ast::VariantData::Unit(..) => rewrite_ident(&context, field.ident).to_owned(),
562 let variant_body = if let Some(ref expr) = field.disr_expr {
563 let lhs = format!("{:1$} =", variant_body, pad_discrim_ident_to);
564 rewrite_assign_rhs_with(
569 RhsTactics::AllowOverflow,
575 combine_strs_with_missing_comments(&context, &attrs_str, &variant_body, span, shape, false)
578 fn visit_impl_items(&mut self, items: &[ast::ImplItem]) {
579 if self.get_context().config.reorder_impl_items() {
580 // Create visitor for each items, then reorder them.
581 let mut buffer = vec![];
583 self.visit_impl_item(item);
584 buffer.push((self.buffer.clone(), item.clone()));
587 // type -> opaque -> const -> macro -> method
588 use crate::ast::ImplItemKind::*;
589 fn need_empty_line(a: &ast::ImplItemKind, b: &ast::ImplItemKind) -> bool {
591 (TyAlias(..), TyAlias(..))
592 | (Const(..), Const(..))
593 | (OpaqueTy(..), OpaqueTy(..)) => false,
598 buffer.sort_by(|(_, a), (_, b)| match (&a.kind, &b.kind) {
599 (TyAlias(..), TyAlias(..))
600 | (Const(..), Const(..))
601 | (Macro(..), Macro(..))
602 | (OpaqueTy(..), OpaqueTy(..)) => a.ident.as_str().cmp(&b.ident.as_str()),
603 (Method(..), Method(..)) => a.span.lo().cmp(&b.span.lo()),
604 (TyAlias(..), _) => Ordering::Less,
605 (_, TyAlias(..)) => Ordering::Greater,
606 (OpaqueTy(..), _) => Ordering::Less,
607 (_, OpaqueTy(..)) => Ordering::Greater,
608 (Const(..), _) => Ordering::Less,
609 (_, Const(..)) => Ordering::Greater,
610 (Macro(..), _) => Ordering::Less,
611 (_, Macro(..)) => Ordering::Greater,
613 let mut prev_kind = None;
614 for (buf, item) in buffer {
615 // Make sure that there are at least a single empty line between
616 // different impl items.
619 .map_or(false, |prev_kind| need_empty_line(prev_kind, &item.kind))
623 let indent_str = self.block_indent.to_string_with_newline(self.config);
624 self.push_str(&indent_str);
625 self.push_str(buf.trim());
626 prev_kind = Some(item.kind.clone());
630 self.visit_impl_item(item);
636 pub(crate) fn format_impl(
637 context: &RewriteContext<'_>,
640 ) -> Option<String> {
641 if let ast::ItemKind::Impl(_, _, _, ref generics, _, ref self_ty, ref items) = item.kind {
642 let mut result = String::with_capacity(128);
643 let ref_and_type = format_impl_ref_and_type(context, item, offset)?;
644 let sep = offset.to_string_with_newline(context.config);
645 result.push_str(&ref_and_type);
647 let where_budget = if result.contains('\n') {
648 context.config.max_width()
650 context.budget(last_line_width(&result))
653 let mut option = WhereClauseOption::snuggled(&ref_and_type);
654 let snippet = context.snippet(item.span);
655 let open_pos = snippet.find_uncommented("{")? + 1;
656 if !contains_comment(&snippet[open_pos..])
658 && generics.where_clause.predicates.len() == 1
659 && !result.contains('\n')
661 option.suppress_comma();
663 option.allow_single_line();
666 let missing_span = mk_sp(self_ty.span.hi(), item.span.hi());
667 let where_span_end = context.snippet_provider.opt_span_before(missing_span, "{");
668 let where_clause_str = rewrite_where_clause(
670 &generics.where_clause,
671 context.config.brace_style(),
672 Shape::legacy(where_budget, offset.block_only()),
680 // If there is no where-clause, we may have missing comments between the trait name and
681 // the opening brace.
682 if generics.where_clause.predicates.is_empty() {
683 if let Some(hi) = where_span_end {
684 match recover_missing_comment_in_span(
685 mk_sp(self_ty.span.hi(), hi),
686 Shape::indented(offset, context.config),
688 last_line_width(&result),
690 Some(ref missing_comment) if !missing_comment.is_empty() => {
691 result.push_str(missing_comment);
698 if is_impl_single_line(context, items, &result, &where_clause_str, item)? {
699 result.push_str(&where_clause_str);
700 if where_clause_str.contains('\n') || last_line_contains_single_line_comment(&result) {
701 // if the where_clause contains extra comments AND
702 // there is only one where-clause predicate
703 // recover the suppressed comma in single line where_clause formatting
704 if generics.where_clause.predicates.len() == 1 {
705 result.push_str(",");
707 result.push_str(&format!("{}{{{}}}", sep, sep));
709 result.push_str(" {}");
714 result.push_str(&where_clause_str);
716 let need_newline = last_line_contains_single_line_comment(&result) || result.contains('\n');
717 match context.config.brace_style() {
718 _ if need_newline => result.push_str(&sep),
719 BraceStyle::AlwaysNextLine => result.push_str(&sep),
720 BraceStyle::PreferSameLine => result.push(' '),
721 BraceStyle::SameLineWhere => {
722 if !where_clause_str.is_empty() {
723 result.push_str(&sep);
731 // this is an impl body snippet(impl SampleImpl { /* here */ })
732 let lo = max(self_ty.span.hi(), generics.where_clause.span.hi());
733 let snippet = context.snippet(mk_sp(lo, item.span.hi()));
734 let open_pos = snippet.find_uncommented("{")? + 1;
736 if !items.is_empty() || contains_comment(&snippet[open_pos..]) {
737 let mut visitor = FmtVisitor::from_context(context);
738 let item_indent = offset.block_only().block_indent(context.config);
739 visitor.block_indent = item_indent;
740 visitor.last_pos = lo + BytePos(open_pos as u32);
742 visitor.visit_attrs(&item.attrs, ast::AttrStyle::Inner);
743 visitor.visit_impl_items(items);
745 visitor.format_missing(item.span.hi() - BytePos(1));
747 let inner_indent_str = visitor.block_indent.to_string_with_newline(context.config);
748 let outer_indent_str = offset.block_only().to_string_with_newline(context.config);
750 result.push_str(&inner_indent_str);
751 result.push_str(visitor.buffer.trim());
752 result.push_str(&outer_indent_str);
753 } else if need_newline || !context.config.empty_item_single_line() {
754 result.push_str(&sep);
765 fn is_impl_single_line(
766 context: &RewriteContext<'_>,
767 items: &[ast::ImplItem],
769 where_clause_str: &str,
772 let snippet = context.snippet(item.span);
773 let open_pos = snippet.find_uncommented("{")? + 1;
776 context.config.empty_item_single_line()
778 && !result.contains('\n')
779 && result.len() + where_clause_str.len() <= context.config.max_width()
780 && !contains_comment(&snippet[open_pos..]),
784 fn format_impl_ref_and_type(
785 context: &RewriteContext<'_>,
788 ) -> Option<String> {
789 if let ast::ItemKind::Impl(
799 let mut result = String::with_capacity(128);
801 result.push_str(&format_visibility(context, &item.vis));
802 result.push_str(format_defaultness(defaultness));
803 result.push_str(format_unsafety(unsafety));
805 let shape = if context.config.version() == Version::Two {
806 Shape::indented(offset + last_line_width(&result), context.config)
808 generics_shape_from_config(
810 Shape::indented(offset + last_line_width(&result), context.config),
814 let generics_str = rewrite_generics(context, "impl", generics, shape)?;
815 result.push_str(&generics_str);
817 let polarity_str = if polarity == ast::ImplPolarity::Negative {
823 if let Some(ref trait_ref) = *trait_ref {
824 let result_len = last_line_width(&result);
825 result.push_str(&rewrite_trait_ref(
834 // Try to put the self type in a single line.
836 let trait_ref_overhead = if trait_ref.is_some() { 4 } else { 0 };
837 let curly_brace_overhead = if generics.where_clause.predicates.is_empty() {
838 // If there is no where-clause adapt budget for type formatting to take space and curly
839 // brace into account.
840 match context.config.brace_style() {
841 BraceStyle::AlwaysNextLine => 0,
847 let used_space = last_line_width(&result) + trait_ref_overhead + curly_brace_overhead;
848 // 1 = space before the type.
849 let budget = context.budget(used_space + 1);
850 if let Some(self_ty_str) = self_ty.rewrite(context, Shape::legacy(budget, offset)) {
851 if !self_ty_str.contains('\n') {
852 if trait_ref.is_some() {
853 result.push_str(" for ");
857 result.push_str(&self_ty_str);
862 // Couldn't fit the self type on a single line, put it on a new line.
864 // Add indentation of one additional tab.
865 let new_line_offset = offset.block_indent(context.config);
866 result.push_str(&new_line_offset.to_string(context.config));
867 if trait_ref.is_some() {
868 result.push_str("for ");
870 let budget = context.budget(last_line_width(&result));
871 let type_offset = match context.config.indent_style() {
872 IndentStyle::Visual => new_line_offset + trait_ref_overhead,
873 IndentStyle::Block => new_line_offset,
875 result.push_str(&*self_ty.rewrite(context, Shape::legacy(budget, type_offset))?);
882 fn rewrite_trait_ref(
883 context: &RewriteContext<'_>,
884 trait_ref: &ast::TraitRef,
888 ) -> Option<String> {
889 // 1 = space between generics and trait_ref
890 let used_space = 1 + polarity_str.len() + result_len;
891 let shape = Shape::indented(offset + used_space, context.config);
892 if let Some(trait_ref_str) = trait_ref.rewrite(context, shape) {
893 if !trait_ref_str.contains('\n') {
894 return Some(format!(" {}{}", polarity_str, trait_ref_str));
897 // We could not make enough space for trait_ref, so put it on new line.
898 let offset = offset.block_indent(context.config);
899 let shape = Shape::indented(offset, context.config);
900 let trait_ref_str = trait_ref.rewrite(context, shape)?;
903 offset.to_string_with_newline(context.config),
909 pub(crate) struct StructParts<'a> {
912 vis: &'a ast::Visibility,
913 def: &'a ast::VariantData,
914 generics: Option<&'a ast::Generics>,
918 impl<'a> StructParts<'a> {
919 fn format_header(&self, context: &RewriteContext<'_>) -> String {
920 format_header(context, self.prefix, self.ident, self.vis)
923 fn from_variant(variant: &'a ast::Variant) -> Self {
926 ident: variant.ident,
927 vis: &DEFAULT_VISIBILITY,
934 pub(crate) fn from_item(item: &'a ast::Item) -> Self {
935 let (prefix, def, generics) = match item.kind {
936 ast::ItemKind::Struct(ref def, ref generics) => ("struct ", def, generics),
937 ast::ItemKind::Union(ref def, ref generics) => ("union ", def, generics),
945 generics: Some(generics),
952 context: &RewriteContext<'_>,
953 struct_parts: &StructParts<'_>,
955 one_line_width: Option<usize>,
956 ) -> Option<String> {
957 match *struct_parts.def {
958 ast::VariantData::Unit(..) => format_unit_struct(context, struct_parts, offset),
959 ast::VariantData::Tuple(ref fields, _) => {
960 format_tuple_struct(context, struct_parts, fields, offset)
962 ast::VariantData::Struct(ref fields, _) => {
963 format_struct_struct(context, struct_parts, fields, offset, one_line_width)
968 pub(crate) fn format_trait(
969 context: &RewriteContext<'_>,
972 ) -> Option<String> {
973 if let ast::ItemKind::Trait(
981 let mut result = String::with_capacity(128);
982 let header = format!(
984 format_visibility(context, &item.vis),
985 format_unsafety(unsafety),
986 format_auto(is_auto),
988 result.push_str(&header);
990 let body_lo = context.snippet_provider.span_after(item.span, "{");
992 let shape = Shape::indented(offset, context.config).offset_left(result.len())?;
994 rewrite_generics(context, rewrite_ident(context, item.ident), generics, shape)?;
995 result.push_str(&generics_str);
997 // FIXME(#2055): rustfmt fails to format when there are comments between trait bounds.
998 if !generic_bounds.is_empty() {
999 let ident_hi = context
1001 .span_after(item.span, &item.ident.as_str());
1002 let bound_hi = generic_bounds.last().unwrap().span().hi();
1003 let snippet = context.snippet(mk_sp(ident_hi, bound_hi));
1004 if contains_comment(snippet) {
1008 result = rewrite_assign_rhs_with(
1013 RhsTactics::ForceNextLineWithoutIndent,
1017 // Rewrite where-clause.
1018 if !generics.where_clause.predicates.is_empty() {
1019 let where_on_new_line = context.config.indent_style() != IndentStyle::Block;
1021 let where_budget = context.budget(last_line_width(&result));
1022 let pos_before_where = if generic_bounds.is_empty() {
1023 generics.where_clause.span.lo()
1025 generic_bounds[generic_bounds.len() - 1].span().hi()
1027 let option = WhereClauseOption::snuggled(&generics_str);
1028 let where_clause_str = rewrite_where_clause(
1030 &generics.where_clause,
1031 context.config.brace_style(),
1032 Shape::legacy(where_budget, offset.block_only()),
1039 // If the where-clause cannot fit on the same line,
1040 // put the where-clause on a new line
1041 if !where_clause_str.contains('\n')
1042 && last_line_width(&result) + where_clause_str.len() + offset.width()
1043 > context.config.comment_width()
1045 let width = offset.block_indent + context.config.tab_spaces() - 1;
1046 let where_indent = Indent::new(0, width);
1047 result.push_str(&where_indent.to_string_with_newline(context.config));
1049 result.push_str(&where_clause_str);
1051 let item_snippet = context.snippet(item.span);
1052 if let Some(lo) = item_snippet.find('/') {
1054 let comment_hi = body_lo - BytePos(1);
1055 let comment_lo = item.span.lo() + BytePos(lo as u32);
1056 if comment_lo < comment_hi {
1057 match recover_missing_comment_in_span(
1058 mk_sp(comment_lo, comment_hi),
1059 Shape::indented(offset, context.config),
1061 last_line_width(&result),
1063 Some(ref missing_comment) if !missing_comment.is_empty() => {
1064 result.push_str(missing_comment);
1072 match context.config.brace_style() {
1073 _ if last_line_contains_single_line_comment(&result)
1074 || last_line_width(&result) + 2 > context.budget(offset.width()) =>
1076 result.push_str(&offset.to_string_with_newline(context.config));
1078 BraceStyle::AlwaysNextLine => {
1079 result.push_str(&offset.to_string_with_newline(context.config));
1081 BraceStyle::PreferSameLine => result.push(' '),
1082 BraceStyle::SameLineWhere => {
1083 if result.contains('\n')
1084 || (!generics.where_clause.predicates.is_empty() && !trait_items.is_empty())
1086 result.push_str(&offset.to_string_with_newline(context.config));
1094 let snippet = context.snippet(item.span);
1095 let open_pos = snippet.find_uncommented("{")? + 1;
1096 let outer_indent_str = offset.block_only().to_string_with_newline(context.config);
1098 if !trait_items.is_empty() || contains_comment(&snippet[open_pos..]) {
1099 let mut visitor = FmtVisitor::from_context(context);
1100 visitor.block_indent = offset.block_only().block_indent(context.config);
1101 visitor.last_pos = item.span.lo() + BytePos(open_pos as u32);
1103 for item in trait_items {
1104 visitor.visit_trait_item(item);
1107 visitor.format_missing(item.span.hi() - BytePos(1));
1109 let inner_indent_str = visitor.block_indent.to_string_with_newline(context.config);
1111 result.push_str(&inner_indent_str);
1112 result.push_str(visitor.buffer.trim());
1113 result.push_str(&outer_indent_str);
1114 } else if result.contains('\n') {
1115 result.push_str(&outer_indent_str);
1125 struct OpaqueTypeBounds<'a> {
1126 generic_bounds: &'a ast::GenericBounds,
1129 impl<'a> Rewrite for OpaqueTypeBounds<'a> {
1130 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
1132 .rewrite(context, shape)
1133 .map(|s| format!("impl {}", s))
1137 pub(crate) struct TraitAliasBounds<'a> {
1138 generic_bounds: &'a ast::GenericBounds,
1139 generics: &'a ast::Generics,
1142 impl<'a> Rewrite for TraitAliasBounds<'a> {
1143 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
1144 let generic_bounds_str = self.generic_bounds.rewrite(context, shape)?;
1146 let mut option = WhereClauseOption::new(true, WhereClauseSpace::None);
1147 option.allow_single_line();
1149 let where_str = rewrite_where_clause(
1151 &self.generics.where_clause,
1152 context.config.brace_style(),
1157 self.generics.where_clause.span.lo(),
1161 let fits_single_line = !generic_bounds_str.contains('\n')
1162 && !where_str.contains('\n')
1163 && generic_bounds_str.len() + where_str.len() + 1 <= shape.width;
1164 let space = if generic_bounds_str.is_empty() || where_str.is_empty() {
1166 } else if fits_single_line {
1169 shape.indent.to_string_with_newline(&context.config)
1172 Some(format!("{}{}{}", generic_bounds_str, space, where_str))
1176 pub(crate) fn format_trait_alias(
1177 context: &RewriteContext<'_>,
1179 vis: &ast::Visibility,
1180 generics: &ast::Generics,
1181 generic_bounds: &ast::GenericBounds,
1183 ) -> Option<String> {
1184 let alias = rewrite_ident(context, ident);
1185 // 6 = "trait ", 2 = " ="
1186 let g_shape = shape.offset_left(6)?.sub_width(2)?;
1187 let generics_str = rewrite_generics(context, &alias, generics, g_shape)?;
1188 let vis_str = format_visibility(context, vis);
1189 let lhs = format!("{}trait {} =", vis_str, generics_str);
1191 let trait_alias_bounds = TraitAliasBounds {
1195 rewrite_assign_rhs(context, lhs, &trait_alias_bounds, shape.sub_width(1)?).map(|s| s + ";")
1198 fn format_unit_struct(
1199 context: &RewriteContext<'_>,
1200 p: &StructParts<'_>,
1202 ) -> Option<String> {
1203 let header_str = format_header(context, p.prefix, p.ident, p.vis);
1204 let generics_str = if let Some(generics) = p.generics {
1205 let hi = context.snippet_provider.span_before(p.span, ";");
1209 context.config.brace_style(),
1212 // make a span that starts right after `struct Foo`
1213 mk_sp(p.ident.span.hi(), hi),
1214 last_line_width(&header_str),
1219 Some(format!("{}{};", header_str, generics_str))
1222 pub(crate) fn format_struct_struct(
1223 context: &RewriteContext<'_>,
1224 struct_parts: &StructParts<'_>,
1225 fields: &[ast::StructField],
1227 one_line_width: Option<usize>,
1228 ) -> Option<String> {
1229 let mut result = String::with_capacity(1024);
1230 let span = struct_parts.span;
1232 let header_str = struct_parts.format_header(context);
1233 result.push_str(&header_str);
1235 let header_hi = struct_parts.ident.span.hi();
1236 let body_lo = context.snippet_provider.span_after(span, "{");
1238 let generics_str = match struct_parts.generics {
1239 Some(g) => format_generics(
1242 context.config.brace_style(),
1243 if fields.is_empty() {
1244 BracePos::ForceSameLine
1249 // make a span that starts right after `struct Foo`
1250 mk_sp(header_hi, body_lo),
1251 last_line_width(&result),
1254 // 3 = ` {}`, 2 = ` {`.
1255 let overhead = if fields.is_empty() { 3 } else { 2 };
1256 if (context.config.brace_style() == BraceStyle::AlwaysNextLine && !fields.is_empty())
1257 || context.config.max_width() < overhead + result.len()
1259 format!("\n{}{{", offset.block_only().to_string(context.config))
1266 let overhead = if fields.is_empty() { 1 } else { 0 };
1267 let total_width = result.len() + generics_str.len() + overhead;
1268 if !generics_str.is_empty()
1269 && !generics_str.contains('\n')
1270 && total_width > context.config.max_width()
1273 result.push_str(&offset.to_string(context.config));
1274 result.push_str(generics_str.trim_start());
1276 result.push_str(&generics_str);
1279 if fields.is_empty() {
1280 let inner_span = mk_sp(body_lo, span.hi() - BytePos(1));
1281 format_empty_struct_or_tuple(context, inner_span, offset, &mut result, "", "}");
1282 return Some(result);
1286 let one_line_budget = context.budget(result.len() + 3 + offset.width());
1287 let one_line_budget =
1288 one_line_width.map_or(0, |one_line_width| min(one_line_width, one_line_budget));
1290 let items_str = rewrite_with_alignment(
1293 Shape::indented(offset.block_indent(context.config), context.config).sub_width(1)?,
1294 mk_sp(body_lo, span.hi()),
1298 if !items_str.contains('\n')
1299 && !result.contains('\n')
1300 && items_str.len() <= one_line_budget
1301 && !last_line_contains_single_line_comment(&items_str)
1303 Some(format!("{} {} }}", result, items_str))
1309 .block_indent(context.config)
1310 .to_string(context.config),
1312 offset.to_string(context.config)
1317 fn get_bytepos_after_visibility(vis: &ast::Visibility, default_span: Span) -> BytePos {
1319 ast::VisibilityKind::Crate(..) | ast::VisibilityKind::Restricted { .. } => vis.span.hi(),
1320 _ => default_span.lo(),
1324 // Format tuple or struct without any fields. We need to make sure that the comments
1325 // inside the delimiters are preserved.
1326 fn format_empty_struct_or_tuple(
1327 context: &RewriteContext<'_>,
1330 result: &mut String,
1334 // 3 = " {}" or "();"
1335 let used_width = last_line_used_width(&result, offset.width()) + 3;
1336 if used_width > context.config.max_width() {
1337 result.push_str(&offset.to_string_with_newline(context.config))
1339 result.push_str(opener);
1340 match rewrite_missing_comment(span, Shape::indented(offset, context.config), context) {
1341 Some(ref s) if s.is_empty() => (),
1343 if !is_single_line(s) || first_line_contains_single_line_comment(s) {
1344 let nested_indent_str = offset
1345 .block_indent(context.config)
1346 .to_string_with_newline(context.config);
1347 result.push_str(&nested_indent_str);
1350 if last_line_contains_single_line_comment(s) {
1351 result.push_str(&offset.to_string_with_newline(context.config));
1354 None => result.push_str(context.snippet(span)),
1356 result.push_str(closer);
1359 fn format_tuple_struct(
1360 context: &RewriteContext<'_>,
1361 struct_parts: &StructParts<'_>,
1362 fields: &[ast::StructField],
1364 ) -> Option<String> {
1365 let mut result = String::with_capacity(1024);
1366 let span = struct_parts.span;
1368 let header_str = struct_parts.format_header(context);
1369 result.push_str(&header_str);
1371 let body_lo = if fields.is_empty() {
1372 let lo = get_bytepos_after_visibility(struct_parts.vis, span);
1375 .span_after(mk_sp(lo, span.hi()), "(")
1379 let body_hi = if fields.is_empty() {
1382 .span_after(mk_sp(body_lo, span.hi()), ")")
1384 // This is a dirty hack to work around a missing `)` from the span of the last field.
1385 let last_arg_span = fields[fields.len() - 1].span;
1388 .opt_span_after(mk_sp(last_arg_span.hi(), span.hi()), ")")
1389 .unwrap_or_else(|| last_arg_span.hi())
1392 let where_clause_str = match struct_parts.generics {
1394 let budget = context.budget(last_line_width(&header_str));
1395 let shape = Shape::legacy(budget, offset);
1396 let generics_str = rewrite_generics(context, "", generics, shape)?;
1397 result.push_str(&generics_str);
1399 let where_budget = context.budget(last_line_width(&result));
1400 let option = WhereClauseOption::new(true, WhereClauseSpace::Newline);
1401 rewrite_where_clause(
1403 &generics.where_clause,
1404 context.config.brace_style(),
1405 Shape::legacy(where_budget, offset.block_only()),
1413 None => "".to_owned(),
1416 if fields.is_empty() {
1417 let body_hi = context
1419 .span_before(mk_sp(body_lo, span.hi()), ")");
1420 let inner_span = mk_sp(body_lo, body_hi);
1421 format_empty_struct_or_tuple(context, inner_span, offset, &mut result, "(", ")");
1423 let shape = Shape::indented(offset, context.config).sub_width(1)?;
1424 result = overflow::rewrite_with_parens(
1430 context.config.width_heuristics().fn_call_width,
1435 if !where_clause_str.is_empty()
1436 && !where_clause_str.contains('\n')
1437 && (result.contains('\n')
1438 || offset.block_indent + result.len() + where_clause_str.len() + 1
1439 > context.config.max_width())
1441 // We need to put the where-clause on a new line, but we didn't
1442 // know that earlier, so the where-clause will not be indented properly.
1445 &(offset.block_only() + (context.config.tab_spaces() - 1)).to_string(context.config),
1448 result.push_str(&where_clause_str);
1453 fn rewrite_type_prefix(
1454 context: &RewriteContext<'_>,
1458 generics: &ast::Generics,
1459 ) -> Option<String> {
1460 let mut result = String::with_capacity(128);
1461 result.push_str(prefix);
1462 let ident_str = rewrite_ident(context, ident);
1465 if generics.params.is_empty() {
1466 result.push_str(ident_str)
1468 let g_shape = Shape::indented(indent, context.config)
1469 .offset_left(result.len())?
1471 let generics_str = rewrite_generics(context, ident_str, generics, g_shape)?;
1472 result.push_str(&generics_str);
1475 let where_budget = context.budget(last_line_width(&result));
1476 let option = WhereClauseOption::snuggled(&result);
1477 let where_clause_str = rewrite_where_clause(
1479 &generics.where_clause,
1480 context.config.brace_style(),
1481 Shape::legacy(where_budget, indent),
1488 result.push_str(&where_clause_str);
1493 fn rewrite_type_item<R: Rewrite>(
1494 context: &RewriteContext<'_>,
1500 generics: &ast::Generics,
1501 vis: &ast::Visibility,
1502 ) -> Option<String> {
1503 let mut result = String::with_capacity(128);
1504 result.push_str(&rewrite_type_prefix(
1507 &format!("{}{} ", format_visibility(context, vis), prefix),
1512 if generics.where_clause.predicates.is_empty() {
1513 result.push_str(suffix);
1515 result.push_str(&indent.to_string_with_newline(context.config));
1516 result.push_str(suffix.trim_start());
1520 let rhs_shape = Shape::indented(indent, context.config).sub_width(1)?;
1521 rewrite_assign_rhs(context, result, rhs, rhs_shape).map(|s| s + ";")
1524 pub(crate) fn rewrite_type_alias(
1525 context: &RewriteContext<'_>,
1529 generics: &ast::Generics,
1530 vis: &ast::Visibility,
1531 ) -> Option<String> {
1532 rewrite_type_item(context, indent, "type", " =", ident, ty, generics, vis)
1535 pub(crate) fn rewrite_opaque_type(
1536 context: &RewriteContext<'_>,
1539 generic_bounds: &ast::GenericBounds,
1540 generics: &ast::Generics,
1541 vis: &ast::Visibility,
1542 ) -> Option<String> {
1543 let opaque_type_bounds = OpaqueTypeBounds { generic_bounds };
1550 &opaque_type_bounds,
1556 fn type_annotation_spacing(config: &Config) -> (&str, &str) {
1558 if config.space_before_colon() { " " } else { "" },
1559 if config.space_after_colon() { " " } else { "" },
1563 pub(crate) fn rewrite_struct_field_prefix(
1564 context: &RewriteContext<'_>,
1565 field: &ast::StructField,
1566 ) -> Option<String> {
1567 let vis = format_visibility(context, &field.vis);
1568 let type_annotation_spacing = type_annotation_spacing(context.config);
1569 Some(match field.ident {
1570 Some(name) => format!(
1573 rewrite_ident(context, name),
1574 type_annotation_spacing.0
1576 None => vis.to_string(),
1580 impl Rewrite for ast::StructField {
1581 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
1582 rewrite_struct_field(context, self, shape, 0)
1586 pub(crate) fn rewrite_struct_field(
1587 context: &RewriteContext<'_>,
1588 field: &ast::StructField,
1590 lhs_max_width: usize,
1591 ) -> Option<String> {
1592 if contains_skip(&field.attrs) {
1593 return Some(context.snippet(field.span()).to_owned());
1596 let type_annotation_spacing = type_annotation_spacing(context.config);
1597 let prefix = rewrite_struct_field_prefix(context, field)?;
1599 let attrs_str = field.attrs.rewrite(context, shape)?;
1600 let attrs_extendable = field.ident.is_none() && is_attributes_extendable(&attrs_str);
1601 let missing_span = if field.attrs.is_empty() {
1602 mk_sp(field.span.lo(), field.span.lo())
1604 mk_sp(field.attrs.last().unwrap().span.hi(), field.span.lo())
1606 let mut spacing = String::from(if field.ident.is_some() {
1607 type_annotation_spacing.1
1611 // Try to put everything on a single line.
1612 let attr_prefix = combine_strs_with_missing_comments(
1620 let overhead = last_line_width(&attr_prefix);
1621 let lhs_offset = lhs_max_width.saturating_sub(overhead);
1622 for _ in 0..lhs_offset {
1625 // In this extreme case we will be missing a space between an attribute and a field.
1626 if prefix.is_empty() && !attrs_str.is_empty() && attrs_extendable && spacing.is_empty() {
1630 .offset_left(overhead + spacing.len())
1631 .and_then(|ty_shape| field.ty.rewrite(context, ty_shape));
1632 if let Some(ref ty) = orig_ty {
1633 if !ty.contains('\n') {
1634 return Some(attr_prefix + &spacing + ty);
1638 let is_prefix_empty = prefix.is_empty();
1639 // We must use multiline. We are going to put attributes and a field on different lines.
1640 let field_str = rewrite_assign_rhs(context, prefix, &*field.ty, shape)?;
1641 // Remove a leading white-space from `rewrite_assign_rhs()` when rewriting a tuple struct.
1642 let field_str = if is_prefix_empty {
1643 field_str.trim_start()
1647 combine_strs_with_missing_comments(context, &attrs_str, field_str, missing_span, shape, false)
1650 pub(crate) struct StaticParts<'a> {
1652 vis: &'a ast::Visibility,
1655 mutability: ast::Mutability,
1656 expr_opt: Option<&'a ptr::P<ast::Expr>>,
1657 defaultness: Option<ast::Defaultness>,
1661 impl<'a> StaticParts<'a> {
1662 pub(crate) fn from_item(item: &'a ast::Item) -> Self {
1663 let (prefix, ty, mutability, expr) = match item.kind {
1664 ast::ItemKind::Static(ref ty, mutability, ref expr) => ("static", ty, mutability, expr),
1665 ast::ItemKind::Const(ref ty, ref expr) => {
1666 ("const", ty, ast::Mutability::Immutable, expr)
1668 _ => unreachable!(),
1676 expr_opt: Some(expr),
1682 pub(crate) fn from_trait_item(ti: &'a ast::TraitItem) -> Self {
1683 let (ty, expr_opt) = match ti.kind {
1684 ast::TraitItemKind::Const(ref ty, ref expr_opt) => (ty, expr_opt),
1685 _ => unreachable!(),
1689 vis: &DEFAULT_VISIBILITY,
1692 mutability: ast::Mutability::Immutable,
1693 expr_opt: expr_opt.as_ref(),
1699 pub(crate) fn from_impl_item(ii: &'a ast::ImplItem) -> Self {
1700 let (ty, expr) = match ii.kind {
1701 ast::ImplItemKind::Const(ref ty, ref expr) => (ty, expr),
1702 _ => unreachable!(),
1709 mutability: ast::Mutability::Immutable,
1710 expr_opt: Some(expr),
1711 defaultness: Some(ii.defaultness),
1718 context: &RewriteContext<'_>,
1719 static_parts: &StaticParts<'_>,
1721 ) -> Option<String> {
1722 let colon = colon_spaces(context.config);
1723 let mut prefix = format!(
1725 format_visibility(context, static_parts.vis),
1726 static_parts.defaultness.map_or("", format_defaultness),
1727 static_parts.prefix,
1728 format_mutability(static_parts.mutability),
1729 rewrite_ident(context, static_parts.ident),
1734 Shape::indented(offset.block_only(), context.config).offset_left(prefix.len() + 2)?;
1735 let ty_str = match static_parts.ty.rewrite(context, ty_shape) {
1736 Some(ty_str) => ty_str,
1738 if prefix.ends_with(' ') {
1741 let nested_indent = offset.block_indent(context.config);
1742 let nested_shape = Shape::indented(nested_indent, context.config);
1743 let ty_str = static_parts.ty.rewrite(context, nested_shape)?;
1746 nested_indent.to_string_with_newline(context.config),
1752 if let Some(expr) = static_parts.expr_opt {
1753 let lhs = format!("{}{} =", prefix, ty_str);
1755 let remaining_width = context.budget(offset.block_indent + 1);
1760 Shape::legacy(remaining_width, offset.block_only()),
1762 .and_then(|res| recover_comment_removed(res, static_parts.span, context))
1763 .map(|s| if s.ends_with(';') { s } else { s + ";" })
1765 Some(format!("{}{};", prefix, ty_str))
1769 pub(crate) fn rewrite_associated_type(
1771 ty_opt: Option<&ptr::P<ast::Ty>>,
1772 generics: &ast::Generics,
1773 generic_bounds_opt: Option<&ast::GenericBounds>,
1774 context: &RewriteContext<'_>,
1776 ) -> Option<String> {
1777 let ident_str = rewrite_ident(context, ident);
1779 let generics_shape = Shape::indented(indent, context.config).offset_left(5)?;
1780 let generics_str = rewrite_generics(context, ident_str, generics, generics_shape)?;
1781 let prefix = format!("type {}", generics_str);
1783 let type_bounds_str = if let Some(bounds) = generic_bounds_opt {
1784 if bounds.is_empty() {
1788 let shape = Shape::indented(indent, context.config).offset_left(prefix.len() + 2)?;
1789 bounds.rewrite(context, shape).map(|s| format!(": {}", s))?
1795 if let Some(ty) = ty_opt {
1797 let shape = Shape::indented(indent, context.config).sub_width(1)?;
1798 let lhs = format!("{}{} =", prefix, type_bounds_str);
1799 rewrite_assign_rhs(context, lhs, &**ty, shape).map(|s| s + ";")
1801 Some(format!("{}{};", prefix, type_bounds_str))
1805 struct OpaqueType<'a> {
1806 bounds: &'a ast::GenericBounds,
1809 impl<'a> Rewrite for OpaqueType<'a> {
1810 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
1811 let shape = shape.offset_left(5)?; // `impl `
1813 .rewrite(context, shape)
1814 .map(|s| format!("impl {}", s))
1818 pub(crate) fn rewrite_opaque_impl_type(
1819 context: &RewriteContext<'_>,
1821 generics: &ast::Generics,
1822 generic_bounds: &ast::GenericBounds,
1824 ) -> Option<String> {
1825 let ident_str = rewrite_ident(context, ident);
1827 let generics_shape = Shape::indented(indent, context.config).offset_left(5)?;
1828 let generics_str = rewrite_generics(context, ident_str, generics, generics_shape)?;
1829 let prefix = format!("type {} =", generics_str);
1830 let rhs = OpaqueType {
1831 bounds: generic_bounds,
1838 Shape::indented(indent, context.config).sub_width(1)?,
1843 pub(crate) fn rewrite_associated_impl_type(
1845 defaultness: ast::Defaultness,
1846 ty_opt: Option<&ptr::P<ast::Ty>>,
1847 generics: &ast::Generics,
1848 context: &RewriteContext<'_>,
1850 ) -> Option<String> {
1851 let result = rewrite_associated_type(ident, ty_opt, generics, None, context, indent)?;
1854 ast::Defaultness::Default => Some(format!("default {}", result)),
1859 impl Rewrite for ast::FunctionRetTy {
1860 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
1862 ast::FunctionRetTy::Default(_) => Some(String::new()),
1863 ast::FunctionRetTy::Ty(ref ty) => {
1864 if context.config.version() == Version::One
1865 || context.config.indent_style() == IndentStyle::Visual
1867 let inner_width = shape.width.checked_sub(3)?;
1869 .rewrite(context, Shape::legacy(inner_width, shape.indent + 3))
1870 .map(|r| format!("-> {}", r));
1873 ty.rewrite(context, shape.offset_left(3)?)
1874 .map(|s| format!("-> {}", s))
1880 fn is_empty_infer(ty: &ast::Ty, pat_span: Span) -> bool {
1882 ast::TyKind::Infer => ty.span.hi() == pat_span.hi(),
1887 /// Recover any missing comments between the param and the type.
1891 /// A 2-len tuple with the comment before the colon in first position, and the comment after the
1892 /// colon in second position.
1893 fn get_missing_param_comments(
1894 context: &RewriteContext<'_>,
1898 ) -> (String, String) {
1899 let missing_comment_span = mk_sp(pat_span.hi(), ty_span.lo());
1901 let span_before_colon = {
1902 let missing_comment_span_hi = context
1904 .span_before(missing_comment_span, ":");
1905 mk_sp(pat_span.hi(), missing_comment_span_hi)
1907 let span_after_colon = {
1908 let missing_comment_span_lo = context
1910 .span_after(missing_comment_span, ":");
1911 mk_sp(missing_comment_span_lo, ty_span.lo())
1914 let comment_before_colon = rewrite_missing_comment(span_before_colon, shape, context)
1915 .filter(|comment| !comment.is_empty())
1916 .map_or(String::new(), |comment| format!(" {}", comment));
1917 let comment_after_colon = rewrite_missing_comment(span_after_colon, shape, context)
1918 .filter(|comment| !comment.is_empty())
1919 .map_or(String::new(), |comment| format!("{} ", comment));
1920 (comment_before_colon, comment_after_colon)
1923 impl Rewrite for ast::Param {
1924 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
1925 let param_attrs_result = self
1927 .rewrite(context, Shape::legacy(shape.width, shape.indent))?;
1928 let (span, has_multiple_attr_lines) = if !self.attrs.is_empty() {
1929 let num_attrs = self.attrs.len();
1931 mk_sp(self.attrs[num_attrs - 1].span.hi(), self.pat.span.lo()),
1932 param_attrs_result.contains("\n"),
1935 (mk_sp(self.span.lo(), self.span.lo()), false)
1938 if let Some(ref explicit_self) = self.to_self() {
1939 rewrite_explicit_self(
1942 ¶m_attrs_result,
1945 has_multiple_attr_lines,
1947 } else if is_named_param(self) {
1948 let mut result = combine_strs_with_missing_comments(
1950 ¶m_attrs_result,
1953 .rewrite(context, Shape::legacy(shape.width, shape.indent))?,
1956 !has_multiple_attr_lines,
1959 if !is_empty_infer(&*self.ty, self.pat.span) {
1960 let (before_comment, after_comment) =
1961 get_missing_param_comments(context, self.pat.span, self.ty.span, shape);
1962 result.push_str(&before_comment);
1963 result.push_str(colon_spaces(context.config));
1964 result.push_str(&after_comment);
1965 let overhead = last_line_width(&result);
1966 let max_width = shape.width.checked_sub(overhead)?;
1969 .rewrite(context, Shape::legacy(max_width, shape.indent))?;
1970 result.push_str(&ty_str);
1975 self.ty.rewrite(context, shape)
1980 fn rewrite_explicit_self(
1981 context: &RewriteContext<'_>,
1982 explicit_self: &ast::ExplicitSelf,
1986 has_multiple_attr_lines: bool,
1987 ) -> Option<String> {
1988 match explicit_self.node {
1989 ast::SelfKind::Region(lt, m) => {
1990 let mut_str = format_mutability(m);
1993 let lifetime_str = l.rewrite(
1995 Shape::legacy(context.config.max_width(), Indent::empty()),
1997 Some(combine_strs_with_missing_comments(
2000 &format!("&{} {}self", lifetime_str, mut_str),
2003 !has_multiple_attr_lines,
2006 None => Some(combine_strs_with_missing_comments(
2009 &format!("&{}self", mut_str),
2012 !has_multiple_attr_lines,
2016 ast::SelfKind::Explicit(ref ty, mutability) => {
2017 let type_str = ty.rewrite(
2019 Shape::legacy(context.config.max_width(), Indent::empty()),
2022 Some(combine_strs_with_missing_comments(
2025 &format!("{}self: {}", format_mutability(mutability), type_str),
2028 !has_multiple_attr_lines,
2031 ast::SelfKind::Value(mutability) => Some(combine_strs_with_missing_comments(
2034 &format!("{}self", format_mutability(mutability)),
2037 !has_multiple_attr_lines,
2042 pub(crate) fn span_lo_for_param(param: &ast::Param) -> BytePos {
2043 if param.attrs.is_empty() {
2044 if is_named_param(param) {
2050 param.attrs[0].span.lo()
2054 pub(crate) fn span_hi_for_param(context: &RewriteContext<'_>, param: &ast::Param) -> BytePos {
2055 match param.ty.kind {
2056 ast::TyKind::Infer if context.snippet(param.ty.span) == "_" => param.ty.span.hi(),
2057 ast::TyKind::Infer if is_named_param(param) => param.pat.span.hi(),
2058 _ => param.ty.span.hi(),
2062 pub(crate) fn is_named_param(param: &ast::Param) -> bool {
2063 if let ast::PatKind::Ident(_, ident, _) = param.pat.kind {
2064 ident.name != symbol::kw::Invalid
2070 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
2071 pub(crate) enum FnBraceStyle {
2077 // Return type is (result, force_new_line_for_brace)
2079 context: &RewriteContext<'_>,
2084 fn_brace_style: FnBraceStyle,
2085 ) -> Option<(String, bool)> {
2086 let mut force_new_line_for_brace = false;
2088 let where_clause = &fn_sig.generics.where_clause;
2090 let mut result = String::with_capacity(1024);
2091 result.push_str(&fn_sig.to_str(context));
2094 result.push_str("fn ");
2097 let overhead = if let FnBraceStyle::SameLine = fn_brace_style {
2104 let used_width = last_line_used_width(&result, indent.width());
2105 let one_line_budget = context.budget(used_width + overhead);
2107 width: one_line_budget,
2111 let fd = fn_sig.decl;
2112 let generics_str = rewrite_generics(
2114 rewrite_ident(context, ident),
2118 result.push_str(&generics_str);
2120 let snuggle_angle_bracket = generics_str
2123 .map_or(false, |l| l.trim_start().len() == 1);
2125 // Note that the width and indent don't really matter, we'll re-layout the
2126 // return type later anyway.
2129 .rewrite(context, Shape::indented(indent, context.config))?;
2131 let multi_line_ret_str = ret_str.contains('\n');
2132 let ret_str_len = if multi_line_ret_str { 0 } else { ret_str.len() };
2135 let (one_line_budget, multi_line_budget, mut param_indent) = compute_budgets_for_params(
2145 "rewrite_fn_base: one_line_budget: {}, multi_line_budget: {}, param_indent: {:?}",
2146 one_line_budget, multi_line_budget, param_indent
2150 // Check if vertical layout was forced.
2151 if one_line_budget == 0
2152 && !snuggle_angle_bracket
2153 && context.config.indent_style() == IndentStyle::Visual
2155 result.push_str(¶m_indent.to_string_with_newline(context.config));
2158 // Skip `pub(crate)`.
2159 let lo_after_visibility = get_bytepos_after_visibility(&fn_sig.visibility, span);
2160 // A conservative estimation, to goal is to be over all parens in generics
2161 let params_start = fn_sig
2166 .map_or(lo_after_visibility, |param| param.span().hi());
2167 let params_end = if fd.inputs.is_empty() {
2170 .span_after(mk_sp(params_start, span.hi()), ")")
2172 let last_span = mk_sp(fd.inputs[fd.inputs.len() - 1].span().hi(), span.hi());
2173 context.snippet_provider.span_after(last_span, ")")
2175 let params_span = mk_sp(
2178 .span_after(mk_sp(params_start, span.hi()), "("),
2181 let param_str = rewrite_params(
2192 let put_params_in_block = match context.config.indent_style() {
2193 IndentStyle::Block => param_str.contains('\n') || param_str.len() > one_line_budget,
2195 } && !fd.inputs.is_empty();
2197 let mut params_last_line_contains_comment = false;
2198 let mut no_params_and_over_max_width = false;
2200 if put_params_in_block {
2201 param_indent = indent.block_indent(context.config);
2202 result.push_str(¶m_indent.to_string_with_newline(context.config));
2203 result.push_str(¶m_str);
2204 result.push_str(&indent.to_string_with_newline(context.config));
2207 result.push_str(¶m_str);
2208 let used_width = last_line_used_width(&result, indent.width()) + first_line_width(&ret_str);
2209 // Put the closing brace on the next line if it overflows the max width.
2211 let closing_paren_overflow_max_width =
2212 fd.inputs.is_empty() && used_width + 1 > context.config.max_width();
2213 // If the last line of params contains comment, we cannot put the closing paren
2214 // on the same line.
2215 params_last_line_contains_comment = param_str
2218 .map_or(false, |last_line| last_line.contains("//"));
2220 if context.config.version() == Version::Two {
2222 if closing_paren_overflow_max_width || params_last_line_contains_comment {
2223 result.push_str(&indent.to_string_with_newline(context.config));
2224 no_params_and_over_max_width = true;
2227 if closing_paren_overflow_max_width || params_last_line_contains_comment {
2228 result.push_str(&indent.to_string_with_newline(context.config));
2235 if let ast::FunctionRetTy::Ty(..) = fd.output {
2236 let ret_should_indent = match context.config.indent_style() {
2237 // If our params are block layout then we surely must have space.
2238 IndentStyle::Block if put_params_in_block || fd.inputs.is_empty() => false,
2239 _ if params_last_line_contains_comment => false,
2240 _ if result.contains('\n') || multi_line_ret_str => true,
2242 // If the return type would push over the max width, then put the return type on
2243 // a new line. With the +1 for the signature length an additional space between
2244 // the closing parenthesis of the param and the arrow '->' is considered.
2245 let mut sig_length = result.len() + indent.width() + ret_str_len + 1;
2247 // If there is no where-clause, take into account the space after the return type
2249 if where_clause.predicates.is_empty() {
2253 sig_length > context.config.max_width()
2256 let ret_shape = if ret_should_indent {
2257 if context.config.version() == Version::One
2258 || context.config.indent_style() == IndentStyle::Visual
2260 let indent = if param_str.is_empty() {
2261 // Aligning with non-existent params looks silly.
2262 force_new_line_for_brace = true;
2265 // FIXME: we might want to check that using the param indent
2266 // doesn't blow our budget, and if it does, then fallback to
2267 // the where-clause indent.
2271 result.push_str(&indent.to_string_with_newline(context.config));
2272 Shape::indented(indent, context.config)
2274 let mut ret_shape = Shape::indented(indent, context.config);
2275 if param_str.is_empty() {
2276 // Aligning with non-existent params looks silly.
2277 force_new_line_for_brace = true;
2278 ret_shape = if context.use_block_indent() {
2279 ret_shape.offset_left(4).unwrap_or(ret_shape)
2281 ret_shape.indent = ret_shape.indent + 4;
2286 result.push_str(&ret_shape.indent.to_string_with_newline(context.config));
2290 if context.config.version() == Version::Two {
2291 if !param_str.is_empty() || !no_params_and_over_max_width {
2298 let ret_shape = Shape::indented(indent, context.config);
2300 .offset_left(last_line_width(&result))
2301 .unwrap_or(ret_shape)
2304 if multi_line_ret_str || ret_should_indent {
2305 // Now that we know the proper indent and width, we need to
2306 // re-layout the return type.
2307 let ret_str = fd.output.rewrite(context, ret_shape)?;
2308 result.push_str(&ret_str);
2310 result.push_str(&ret_str);
2313 // Comment between return type and the end of the decl.
2314 let snippet_lo = fd.output.span().hi();
2315 if where_clause.predicates.is_empty() {
2316 let snippet_hi = span.hi();
2317 let snippet = context.snippet(mk_sp(snippet_lo, snippet_hi));
2318 // Try to preserve the layout of the original snippet.
2319 let original_starts_with_newline = snippet
2321 .map_or(false, |i| starts_with_newline(&snippet[i..]));
2322 let original_ends_with_newline = snippet
2323 .rfind(|c| c != ' ')
2324 .map_or(false, |i| snippet[i..].ends_with('\n'));
2325 let snippet = snippet.trim();
2326 if !snippet.is_empty() {
2327 result.push(if original_starts_with_newline {
2332 result.push_str(snippet);
2333 if original_ends_with_newline {
2334 force_new_line_for_brace = true;
2340 let pos_before_where = match fd.output {
2341 ast::FunctionRetTy::Default(..) => params_span.hi(),
2342 ast::FunctionRetTy::Ty(ref ty) => ty.span.hi(),
2345 let is_params_multi_lined = param_str.contains('\n');
2347 let space = if put_params_in_block && ret_str.is_empty() {
2348 WhereClauseSpace::Space
2350 WhereClauseSpace::Newline
2352 let mut option = WhereClauseOption::new(fn_brace_style == FnBraceStyle::None, space);
2353 if is_params_multi_lined {
2354 option.veto_single_line();
2356 let where_clause_str = rewrite_where_clause(
2359 context.config.brace_style(),
2360 Shape::indented(indent, context.config),
2367 // If there are neither where-clause nor return type, we may be missing comments between
2369 if where_clause_str.is_empty() {
2370 if let ast::FunctionRetTy::Default(ret_span) = fd.output {
2371 match recover_missing_comment_in_span(
2372 mk_sp(params_span.hi(), ret_span.hi()),
2375 last_line_width(&result),
2377 Some(ref missing_comment) if !missing_comment.is_empty() => {
2378 result.push_str(missing_comment);
2379 force_new_line_for_brace = true;
2386 result.push_str(&where_clause_str);
2388 force_new_line_for_brace |= last_line_contains_single_line_comment(&result);
2389 force_new_line_for_brace |= is_params_multi_lined && context.config.where_single_line();
2390 Some((result, force_new_line_for_brace))
2393 /// Kind of spaces to put before `where`.
2394 #[derive(Copy, Clone)]
2395 enum WhereClauseSpace {
2404 #[derive(Copy, Clone)]
2405 struct WhereClauseOption {
2406 suppress_comma: bool, // Force no trailing comma
2407 snuggle: WhereClauseSpace,
2408 allow_single_line: bool, // Try single line where-clause instead of vertical layout
2409 veto_single_line: bool, // Disallow a single-line where-clause.
2412 impl WhereClauseOption {
2413 fn new(suppress_comma: bool, snuggle: WhereClauseSpace) -> WhereClauseOption {
2417 allow_single_line: false,
2418 veto_single_line: false,
2422 fn snuggled(current: &str) -> WhereClauseOption {
2424 suppress_comma: false,
2425 snuggle: if last_line_width(current) == 1 {
2426 WhereClauseSpace::Space
2428 WhereClauseSpace::Newline
2430 allow_single_line: false,
2431 veto_single_line: false,
2435 fn suppress_comma(&mut self) {
2436 self.suppress_comma = true
2439 fn allow_single_line(&mut self) {
2440 self.allow_single_line = true
2443 fn snuggle(&mut self) {
2444 self.snuggle = WhereClauseSpace::Space
2447 fn veto_single_line(&mut self) {
2448 self.veto_single_line = true;
2453 context: &RewriteContext<'_>,
2454 params: &[ast::Param],
2455 one_line_budget: usize,
2456 multi_line_budget: usize,
2458 param_indent: Indent,
2461 ) -> Option<String> {
2462 if params.is_empty() {
2463 let comment = context
2467 span.hi() - BytePos(1),
2470 return Some(comment.to_owned());
2472 let param_items: Vec<_> = itemize_list(
2473 context.snippet_provider,
2477 |param| span_lo_for_param(param),
2478 |param| param.ty.span.hi(),
2481 .rewrite(context, Shape::legacy(multi_line_budget, param_indent))
2482 .or_else(|| Some(context.snippet(param.span()).to_owned()))
2490 let tactic = definitive_tactic(
2495 .to_list_tactic(param_items.len()),
2499 let budget = match tactic {
2500 DefinitiveListTactic::Horizontal => one_line_budget,
2501 _ => multi_line_budget,
2503 let indent = match context.config.indent_style() {
2504 IndentStyle::Block => indent.block_indent(context.config),
2505 IndentStyle::Visual => param_indent,
2507 let trailing_separator = if variadic {
2508 SeparatorTactic::Never
2510 match context.config.indent_style() {
2511 IndentStyle::Block => context.config.trailing_comma(),
2512 IndentStyle::Visual => SeparatorTactic::Never,
2515 let fmt = ListFormatting::new(Shape::legacy(budget, indent), context.config)
2517 .trailing_separator(trailing_separator)
2518 .ends_with_newline(tactic.ends_with_newline(context.config.indent_style()))
2519 .preserve_newline(true);
2520 write_list(¶m_items, &fmt)
2523 fn compute_budgets_for_params(
2524 context: &RewriteContext<'_>,
2528 fn_brace_style: FnBraceStyle,
2529 force_vertical_layout: bool,
2530 ) -> Option<((usize, usize, Indent))> {
2532 "compute_budgets_for_params {} {:?}, {}, {:?}",
2538 // Try keeping everything on the same line.
2539 if !result.contains('\n') && !force_vertical_layout {
2540 // 2 = `()`, 3 = `() `, space is before ret_string.
2541 let overhead = if ret_str_len == 0 { 2 } else { 3 };
2542 let mut used_space = indent.width() + result.len() + ret_str_len + overhead;
2543 match fn_brace_style {
2544 FnBraceStyle::None => used_space += 1, // 1 = `;`
2545 FnBraceStyle::SameLine => used_space += 2, // 2 = `{}`
2546 FnBraceStyle::NextLine => (),
2548 let one_line_budget = context.budget(used_space);
2550 if one_line_budget > 0 {
2552 let (indent, multi_line_budget) = match context.config.indent_style() {
2553 IndentStyle::Block => {
2554 let indent = indent.block_indent(context.config);
2555 (indent, context.budget(indent.width() + 1))
2557 IndentStyle::Visual => {
2558 let indent = indent + result.len() + 1;
2559 let multi_line_overhead = match fn_brace_style {
2560 FnBraceStyle::SameLine => 4,
2563 (indent, context.budget(multi_line_overhead))
2567 return Some((one_line_budget, multi_line_budget, indent));
2571 // Didn't work. we must force vertical layout and put params on a newline.
2572 let new_indent = indent.block_indent(context.config);
2573 let used_space = match context.config.indent_style() {
2575 IndentStyle::Block => new_indent.width() + 1,
2576 // Account for `)` and possibly ` {`.
2577 IndentStyle::Visual => new_indent.width() + if ret_str_len == 0 { 1 } else { 3 },
2579 Some((0, context.budget(used_space), new_indent))
2582 fn newline_for_brace(config: &Config, where_clause: &ast::WhereClause) -> FnBraceStyle {
2583 let predicate_count = where_clause.predicates.len();
2585 if config.where_single_line() && predicate_count == 1 {
2586 return FnBraceStyle::SameLine;
2588 let brace_style = config.brace_style();
2590 let use_next_line = brace_style == BraceStyle::AlwaysNextLine
2591 || (brace_style == BraceStyle::SameLineWhere && predicate_count > 0);
2593 FnBraceStyle::NextLine
2595 FnBraceStyle::SameLine
2599 fn rewrite_generics(
2600 context: &RewriteContext<'_>,
2602 generics: &ast::Generics,
2604 ) -> Option<String> {
2605 // FIXME: convert bounds to where-clauses where they get too big or if
2606 // there is a where-clause at all.
2608 if generics.params.is_empty() {
2609 return Some(ident.to_owned());
2612 let params = generics.params.iter();
2613 overflow::rewrite_with_angle_brackets(context, ident, params, shape, generics.span)
2616 fn generics_shape_from_config(config: &Config, shape: Shape, offset: usize) -> Option<Shape> {
2617 match config.indent_style() {
2618 IndentStyle::Visual => shape.visual_indent(1 + offset).sub_width(offset + 2),
2619 IndentStyle::Block => {
2623 .block_indent(config.tab_spaces())
2624 .with_max_width(config)
2630 fn rewrite_where_clause_rfc_style(
2631 context: &RewriteContext<'_>,
2632 where_clause: &ast::WhereClause,
2635 span_end: Option<BytePos>,
2636 span_end_before_where: BytePos,
2637 where_clause_option: WhereClauseOption,
2638 ) -> Option<String> {
2639 let (where_keyword, allow_single_line) = rewrite_where_keyword(
2643 span_end_before_where,
2644 where_clause_option,
2648 let clause_shape = shape
2650 .with_max_width(context.config)
2651 .block_left(context.config.tab_spaces())?
2653 let force_single_line = context.config.where_single_line()
2654 && where_clause.predicates.len() == 1
2655 && !where_clause_option.veto_single_line;
2657 let preds_str = rewrite_bounds_on_where_clause(
2663 where_clause_option,
2669 if allow_single_line && !preds_str.contains('\n') && 6 + preds_str.len() <= shape.width
2670 || force_single_line
2674 clause_shape.indent.to_string_with_newline(context.config)
2677 Some(format!("{}{}{}", where_keyword, clause_sep, preds_str))
2680 /// Rewrite `where` and comment around it.
2681 fn rewrite_where_keyword(
2682 context: &RewriteContext<'_>,
2683 where_clause: &ast::WhereClause,
2685 span_end_before_where: BytePos,
2686 where_clause_option: WhereClauseOption,
2687 ) -> Option<(String, bool)> {
2688 let block_shape = shape.block().with_max_width(context.config);
2690 let clause_shape = block_shape
2691 .block_left(context.config.tab_spaces())?
2694 let comment_separator = |comment: &str, shape: Shape| {
2695 if comment.is_empty() {
2698 shape.indent.to_string_with_newline(context.config)
2702 let (span_before, span_after) =
2703 missing_span_before_after_where(span_end_before_where, where_clause);
2704 let (comment_before, comment_after) =
2705 rewrite_comments_before_after_where(context, span_before, span_after, shape)?;
2707 let starting_newline = match where_clause_option.snuggle {
2708 WhereClauseSpace::Space if comment_before.is_empty() => Cow::from(" "),
2709 WhereClauseSpace::None => Cow::from(""),
2710 _ => block_shape.indent.to_string_with_newline(context.config),
2713 let newline_before_where = comment_separator(&comment_before, shape);
2714 let newline_after_where = comment_separator(&comment_after, clause_shape);
2715 let result = format!(
2717 starting_newline, comment_before, newline_before_where, newline_after_where, comment_after
2719 let allow_single_line = where_clause_option.allow_single_line
2720 && comment_before.is_empty()
2721 && comment_after.is_empty();
2723 Some((result, allow_single_line))
2726 /// Rewrite bounds on a where clause.
2727 fn rewrite_bounds_on_where_clause(
2728 context: &RewriteContext<'_>,
2729 where_clause: &ast::WhereClause,
2732 span_end: Option<BytePos>,
2733 where_clause_option: WhereClauseOption,
2734 force_single_line: bool,
2735 ) -> Option<String> {
2736 let span_start = where_clause.predicates[0].span().lo();
2737 // If we don't have the start of the next span, then use the end of the
2738 // predicates, but that means we miss comments.
2739 let len = where_clause.predicates.len();
2740 let end_of_preds = where_clause.predicates[len - 1].span().hi();
2741 let span_end = span_end.unwrap_or(end_of_preds);
2742 let items = itemize_list(
2743 context.snippet_provider,
2744 where_clause.predicates.iter(),
2747 |pred| pred.span().lo(),
2748 |pred| pred.span().hi(),
2749 |pred| pred.rewrite(context, shape),
2754 let comma_tactic = if where_clause_option.suppress_comma || force_single_line {
2755 SeparatorTactic::Never
2757 context.config.trailing_comma()
2760 // shape should be vertical only and only if we have `force_single_line` option enabled
2761 // and the number of items of the where-clause is equal to 1
2762 let shape_tactic = if force_single_line {
2763 DefinitiveListTactic::Horizontal
2765 DefinitiveListTactic::Vertical
2768 let fmt = ListFormatting::new(shape, context.config)
2769 .tactic(shape_tactic)
2770 .trailing_separator(comma_tactic)
2771 .preserve_newline(true);
2772 write_list(&items.collect::<Vec<_>>(), &fmt)
2775 fn rewrite_where_clause(
2776 context: &RewriteContext<'_>,
2777 where_clause: &ast::WhereClause,
2778 brace_style: BraceStyle,
2782 span_end: Option<BytePos>,
2783 span_end_before_where: BytePos,
2784 where_clause_option: WhereClauseOption,
2785 ) -> Option<String> {
2786 if where_clause.predicates.is_empty() {
2787 return Some(String::new());
2790 if context.config.indent_style() == IndentStyle::Block {
2791 return rewrite_where_clause_rfc_style(
2797 span_end_before_where,
2798 where_clause_option,
2802 let extra_indent = Indent::new(context.config.tab_spaces(), 0);
2804 let offset = match context.config.indent_style() {
2805 IndentStyle::Block => shape.indent + extra_indent.block_indent(context.config),
2806 // 6 = "where ".len()
2807 IndentStyle::Visual => shape.indent + extra_indent + 6,
2809 // FIXME: if indent_style != Visual, then the budgets below might
2810 // be out by a char or two.
2812 let budget = context.config.max_width() - offset.width();
2813 let span_start = where_clause.predicates[0].span().lo();
2814 // If we don't have the start of the next span, then use the end of the
2815 // predicates, but that means we miss comments.
2816 let len = where_clause.predicates.len();
2817 let end_of_preds = where_clause.predicates[len - 1].span().hi();
2818 let span_end = span_end.unwrap_or(end_of_preds);
2819 let items = itemize_list(
2820 context.snippet_provider,
2821 where_clause.predicates.iter(),
2824 |pred| pred.span().lo(),
2825 |pred| pred.span().hi(),
2826 |pred| pred.rewrite(context, Shape::legacy(budget, offset)),
2831 let item_vec = items.collect::<Vec<_>>();
2832 // FIXME: we don't need to collect here
2833 let tactic = definitive_tactic(&item_vec, ListTactic::Vertical, Separator::Comma, budget);
2835 let mut comma_tactic = context.config.trailing_comma();
2836 // Kind of a hack because we don't usually have trailing commas in where-clauses.
2837 if comma_tactic == SeparatorTactic::Vertical || where_clause_option.suppress_comma {
2838 comma_tactic = SeparatorTactic::Never;
2841 let fmt = ListFormatting::new(Shape::legacy(budget, offset), context.config)
2843 .trailing_separator(comma_tactic)
2844 .ends_with_newline(tactic.ends_with_newline(context.config.indent_style()))
2845 .preserve_newline(true);
2846 let preds_str = write_list(&item_vec, &fmt)?;
2848 let end_length = if terminator == "{" {
2849 // If the brace is on the next line we don't need to count it otherwise it needs two
2852 BraceStyle::AlwaysNextLine | BraceStyle::SameLineWhere => 0,
2853 BraceStyle::PreferSameLine => 2,
2855 } else if terminator == "=" {
2861 || preds_str.contains('\n')
2862 || shape.indent.width() + " where ".len() + preds_str.len() + end_length > shape.width
2866 (shape.indent + extra_indent).to_string(context.config),
2870 Some(format!(" where {}", preds_str))
2874 fn missing_span_before_after_where(
2875 before_item_span_end: BytePos,
2876 where_clause: &ast::WhereClause,
2878 let missing_span_before = mk_sp(before_item_span_end, where_clause.span.lo());
2880 let pos_after_where = where_clause.span.lo() + BytePos(5);
2881 let missing_span_after = mk_sp(pos_after_where, where_clause.predicates[0].span().lo());
2882 (missing_span_before, missing_span_after)
2885 fn rewrite_comments_before_after_where(
2886 context: &RewriteContext<'_>,
2887 span_before_where: Span,
2888 span_after_where: Span,
2890 ) -> Option<(String, String)> {
2891 let before_comment = rewrite_missing_comment(span_before_where, shape, context)?;
2892 let after_comment = rewrite_missing_comment(
2894 shape.block_indent(context.config.tab_spaces()),
2897 Some((before_comment, after_comment))
2901 context: &RewriteContext<'_>,
2904 vis: &ast::Visibility,
2908 format_visibility(context, vis),
2910 rewrite_ident(context, ident)
2914 #[derive(PartialEq, Eq, Clone, Copy)]
2922 context: &RewriteContext<'_>,
2923 generics: &ast::Generics,
2924 brace_style: BraceStyle,
2925 brace_pos: BracePos,
2929 ) -> Option<String> {
2930 let shape = Shape::legacy(context.budget(used_width + offset.width()), offset);
2931 let mut result = rewrite_generics(context, "", generics, shape)?;
2933 // If the generics are not parameterized then generics.span.hi() == 0,
2934 // so we use span.lo(), which is the position after `struct Foo`.
2935 let span_end_before_where = if !generics.params.is_empty() {
2940 let (same_line_brace, missed_comments) = if !generics.where_clause.predicates.is_empty() {
2941 let budget = context.budget(last_line_used_width(&result, offset.width()));
2942 let mut option = WhereClauseOption::snuggled(&result);
2943 if brace_pos == BracePos::None {
2944 option.suppress_comma = true;
2946 let where_clause_str = rewrite_where_clause(
2948 &generics.where_clause,
2950 Shape::legacy(budget, offset.block_only()),
2954 span_end_before_where,
2957 result.push_str(&where_clause_str);
2959 brace_pos == BracePos::ForceSameLine || brace_style == BraceStyle::PreferSameLine,
2960 // missed comments are taken care of in #rewrite_where_clause
2965 brace_pos == BracePos::ForceSameLine
2966 || (result.contains('\n') && brace_style == BraceStyle::PreferSameLine
2967 || brace_style != BraceStyle::AlwaysNextLine)
2968 || trimmed_last_line_width(&result) == 1,
2969 rewrite_missing_comment(
2971 span_end_before_where,
2972 if brace_pos == BracePos::None {
2975 context.snippet_provider.span_before(span, "{")
2983 // add missing comments
2984 let missed_line_comments = missed_comments
2985 .filter(|missed_comments| !missed_comments.is_empty())
2986 .map_or(false, |missed_comments| {
2987 let is_block = is_last_comment_block(&missed_comments);
2988 let sep = if is_block { " " } else { "\n" };
2989 result.push_str(sep);
2990 result.push_str(&missed_comments);
2993 if brace_pos == BracePos::None {
2994 return Some(result);
2996 let total_used_width = last_line_used_width(&result, used_width);
2997 let remaining_budget = context.budget(total_used_width);
2998 // If the same line brace if forced, it indicates that we are rewriting an item with empty body,
2999 // and hence we take the closer into account as well for one line budget.
3000 // We assume that the closer has the same length as the opener.
3001 let overhead = if brace_pos == BracePos::ForceSameLine {
3008 let forbid_same_line_brace = missed_line_comments || overhead > remaining_budget;
3009 if !forbid_same_line_brace && same_line_brace {
3013 result.push_str(&offset.block_only().to_string(context.config));
3020 impl Rewrite for ast::ForeignItem {
3021 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
3022 let attrs_str = self.attrs.rewrite(context, shape)?;
3023 // Drop semicolon or it will be interpreted as comment.
3024 // FIXME: this may be a faulty span from libsyntax.
3025 let span = mk_sp(self.span.lo(), self.span.hi() - BytePos(1));
3027 let item_str = match self.kind {
3028 ast::ForeignItemKind::Fn(ref fn_decl, ref generics) => rewrite_fn_base(
3032 &FnSig::new(fn_decl, generics, self.vis.clone()),
3036 .map(|(s, _)| format!("{};", s)),
3037 ast::ForeignItemKind::Static(ref ty, mutability) => {
3038 // FIXME(#21): we're dropping potential comments in between the
3039 // function kw here.
3040 let vis = format_visibility(context, &self.vis);
3041 let mut_str = format_mutability(mutability);
3042 let prefix = format!(
3046 rewrite_ident(context, self.ident)
3049 rewrite_assign_rhs(context, prefix, &**ty, shape.sub_width(1)?).map(|s| s + ";")
3051 ast::ForeignItemKind::Ty => {
3052 let vis = format_visibility(context, &self.vis);
3056 rewrite_ident(context, self.ident)
3059 ast::ForeignItemKind::Macro(ref mac) => {
3060 rewrite_macro(mac, None, context, shape, MacroPosition::Item)
3064 let missing_span = if self.attrs.is_empty() {
3065 mk_sp(self.span.lo(), self.span.lo())
3067 mk_sp(self.attrs[self.attrs.len() - 1].span.hi(), self.span.lo())
3069 combine_strs_with_missing_comments(
3080 /// Rewrite the attributes of an item.
3082 context: &RewriteContext<'_>,
3086 ) -> Option<String> {
3087 let attrs = filter_inline_attrs(&item.attrs, item.span());
3088 let attrs_str = attrs.rewrite(context, shape)?;
3090 let missed_span = if attrs.is_empty() {
3091 mk_sp(item.span.lo(), item.span.lo())
3093 mk_sp(attrs[attrs.len() - 1].span.hi(), item.span.lo())
3096 let allow_extend = if attrs.len() == 1 {
3097 let line_len = attrs_str.len() + 1 + item_str.len();
3098 !attrs.first().unwrap().is_sugared_doc
3099 && context.config.inline_attribute_width() >= line_len
3104 combine_strs_with_missing_comments(
3114 /// Rewrite an inline mod.
3115 /// The given shape is used to format the mod's attributes.
3116 pub(crate) fn rewrite_mod(
3117 context: &RewriteContext<'_>,
3120 ) -> Option<String> {
3121 let mut result = String::with_capacity(32);
3122 result.push_str(&*format_visibility(context, &item.vis));
3123 result.push_str("mod ");
3124 result.push_str(rewrite_ident(context, item.ident));
3126 rewrite_attrs(context, item, &result, attrs_shape)
3129 /// Rewrite `extern crate foo;`.
3130 /// The given shape is used to format the extern crate's attributes.
3131 pub(crate) fn rewrite_extern_crate(
3132 context: &RewriteContext<'_>,
3135 ) -> Option<String> {
3136 assert!(is_extern_crate(item));
3137 let new_str = context.snippet(item.span);
3138 let item_str = if contains_comment(new_str) {
3141 let no_whitespace = &new_str.split_whitespace().collect::<Vec<&str>>().join(" ");
3142 String::from(&*Regex::new(r"\s;").unwrap().replace(no_whitespace, ";"))
3144 rewrite_attrs(context, item, &item_str, attrs_shape)
3147 /// Returns `true` for `mod foo;`, false for `mod foo { .. }`.
3148 pub(crate) fn is_mod_decl(item: &ast::Item) -> bool {
3150 ast::ItemKind::Mod(ref m) => m.inner.hi() != item.span.hi(),
3155 pub(crate) fn is_use_item(item: &ast::Item) -> bool {
3157 ast::ItemKind::Use(_) => true,
3162 pub(crate) fn is_extern_crate(item: &ast::Item) -> bool {
3164 ast::ItemKind::ExternCrate(..) => true,