X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fitems.rs;h=e10265df0effe0b4e98b40cfb0ed4a4cd56d6539;hb=383306e5feaddf71314653a7a39018bbe03e080e;hp=b272a42ba18b753a00327dd2cee085df41eed37c;hpb=4bb90f5cc8e0347534436612f45a3c22c7e265bb;p=rust.git diff --git a/src/items.rs b/src/items.rs index b272a42ba18..e10265df0ef 100644 --- a/src/items.rs +++ b/src/items.rs @@ -1,17 +1,7 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - // Formatting top-level items - functions, structs, enums, traits, impls. use std::borrow::Cow; -use std::cmp::{min, Ordering}; +use std::cmp::{max, min, Ordering}; use regex::Regex; use rustc_target::spec::abi; @@ -19,25 +9,25 @@ use syntax::visit; use syntax::{ast, ptr, symbol}; +use crate::attr::filter_inline_attrs; use crate::comment::{ - combine_strs_with_missing_comments, contains_comment, recover_comment_removed, - recover_missing_comment_in_span, rewrite_missing_comment, FindUncommented, + combine_strs_with_missing_comments, contains_comment, is_last_comment_block, + recover_comment_removed, recover_missing_comment_in_span, rewrite_missing_comment, + FindUncommented, }; use crate::config::lists::*; -use crate::config::{BraceStyle, Config, Density, IndentStyle, Version}; +use crate::config::{BraceStyle, Config, IndentStyle, Version}; use crate::expr::{ - format_expr, is_empty_block, is_simple_block_stmt, rewrite_assign_rhs, rewrite_assign_rhs_with, - ExprType, RhsTactics, -}; -use crate::lists::{ - definitive_tactic, itemize_list, write_list, ListFormatting, ListItem, Separator, + is_empty_block, is_simple_block_stmt, rewrite_assign_rhs, rewrite_assign_rhs_with, RhsTactics, }; +use crate::lists::{definitive_tactic, itemize_list, write_list, ListFormatting, Separator}; use crate::macros::{rewrite_macro, MacroPosition}; use crate::overflow; use crate::rewrite::{Rewrite, RewriteContext}; use crate::shape::{Indent, Shape}; use crate::source_map::{LineRangeUtils, SpanUtils}; use crate::spanned::Spanned; +use crate::stmt::Stmt; use crate::utils::*; use crate::vertical::rewrite_with_alignment; use crate::visitor::FmtVisitor; @@ -48,7 +38,7 @@ }; fn type_annotation_separator(config: &Config) -> &str { - colon_spaces(config.space_before_colon(), config.space_after_colon()) + colon_spaces(config) } // Statements of the form @@ -168,11 +158,11 @@ enum BodyElement<'a> { } /// Represents a fn's signature. -pub struct FnSig<'a> { +pub(crate) struct FnSig<'a> { decl: &'a ast::FnDecl, generics: &'a ast::Generics, abi: abi::Abi, - is_async: ast::IsAsync, + is_async: Cow<'a, ast::IsAsync>, constness: ast::Constness, defaultness: ast::Defaultness, unsafety: ast::Unsafety, @@ -180,7 +170,7 @@ pub struct FnSig<'a> { } impl<'a> FnSig<'a> { - pub fn new( + pub(crate) fn new( decl: &'a ast::FnDecl, generics: &'a ast::Generics, vis: ast::Visibility, @@ -189,7 +179,7 @@ pub fn new( decl, generics, abi: abi::Abi::Rust, - is_async: ast::IsAsync::NotAsync, + is_async: Cow::Owned(ast::IsAsync::NotAsync), constness: ast::Constness::NotConst, defaultness: ast::Defaultness::Final, unsafety: ast::Unsafety::Normal, @@ -197,13 +187,13 @@ pub fn new( } } - pub fn from_method_sig( + pub(crate) fn from_method_sig( method_sig: &'a ast::MethodSig, generics: &'a ast::Generics, ) -> FnSig<'a> { FnSig { unsafety: method_sig.header.unsafety, - is_async: method_sig.header.asyncness, + is_async: Cow::Borrowed(&method_sig.header.asyncness.node), constness: method_sig.header.constness.node, defaultness: ast::Defaultness::Final, abi: method_sig.header.abi, @@ -213,7 +203,7 @@ pub fn from_method_sig( } } - pub fn from_fn_kind( + pub(crate) fn from_fn_kind( fn_kind: &'a visit::FnKind<'_>, generics: &'a ast::Generics, decl: &'a ast::FnDecl, @@ -225,7 +215,7 @@ pub fn from_fn_kind( generics, abi: fn_header.abi, constness: fn_header.constness.node, - is_async: fn_header.asyncness, + is_async: Cow::Borrowed(&fn_header.asyncness.node), defaultness, unsafety: fn_header.unsafety, visibility: visibility.clone(), @@ -248,8 +238,8 @@ fn to_str(&self, context: &RewriteContext<'_>) -> String { result.push_str(&*format_visibility(context, &self.visibility)); result.push_str(format_defaultness(self.defaultness)); result.push_str(format_constness(self.constness)); + result.push_str(format_async(&self.is_async)); result.push_str(format_unsafety(self.unsafety)); - result.push_str(format_async(self.is_async)); result.push_str(&format_abi( self.abi, context.config.force_explicit_abi(), @@ -298,7 +288,7 @@ fn format_body_element(&mut self, element: &BodyElement<'_>) { } } - pub fn format_foreign_mod(&mut self, fm: &ast::ForeignMod, span: Span) { + pub(crate) fn format_foreign_mod(&mut self, fm: &ast::ForeignMod, span: Span) { let item = Item::from_foreign_mod(fm, span, self.config); self.format_item(&item); } @@ -309,50 +299,31 @@ fn format_foreign_item(&mut self, item: &ast::ForeignItem) { self.last_pos = item.span.hi(); } - pub fn rewrite_fn( + pub(crate) fn rewrite_fn_before_block( &mut self, indent: Indent, ident: ast::Ident, fn_sig: &FnSig<'_>, span: Span, - block: &ast::Block, - inner_attrs: Option<&[ast::Attribute]>, - ) -> Option { + ) -> Option<(String, FnBraceStyle)> { let context = self.get_context(); - let mut newline_brace = newline_for_brace(self.config, &fn_sig.generics.where_clause); - - let (mut result, force_newline_brace) = - rewrite_fn_base(&context, indent, ident, fn_sig, span, newline_brace, true)?; + let mut fn_brace_style = newline_for_brace(self.config, &fn_sig.generics.where_clause); + let (result, force_newline_brace) = + rewrite_fn_base(&context, indent, ident, fn_sig, span, fn_brace_style)?; // 2 = ` {` if self.config.brace_style() == BraceStyle::AlwaysNextLine || force_newline_brace || last_line_width(&result) + 2 > self.shape().width { - newline_brace = true; - } else if !result.contains('\n') { - newline_brace = false; + fn_brace_style = FnBraceStyle::NextLine } - if let rw @ Some(..) = self.single_line_fn(&result, block, inner_attrs) { - rw - } else { - // Prepare for the function body by possibly adding a newline and - // indent. - // FIXME we'll miss anything between the end of the signature and the - // start of the body, but we need more spans from the compiler to solve - // this. - if newline_brace { - result.push_str(&indent.to_string_with_newline(self.config)); - } else { - result.push(' '); - } - Some(result) - } + Some((result, fn_brace_style)) } - pub fn rewrite_required_fn( + pub(crate) fn rewrite_required_fn( &mut self, indent: Indent, ident: ast::Ident, @@ -370,8 +341,7 @@ pub fn rewrite_required_fn( ident, &FnSig::from_method_sig(sig, generics), span, - false, - false, + FnBraceStyle::None, )?; // Re-attach semicolon @@ -380,7 +350,7 @@ pub fn rewrite_required_fn( Some(result) } - fn single_line_fn( + pub(crate) fn single_line_fn( &self, fn_str: &str, block: &ast::Block, @@ -404,20 +374,8 @@ fn single_line_fn( return None; } - let stmt = block.stmts.first()?; - let res = match stmt_expr(stmt) { - Some(e) => { - let suffix = if semicolon_for_expr(&self.get_context(), e) { - ";" - } else { - "" - }; - - format_expr(e, ExprType::Statement, &self.get_context(), self.shape()) - .map(|s| s + suffix)? - } - None => stmt.rewrite(&self.get_context(), self.shape())?, - }; + let res = Stmt::from_ast_node(block.stmts.first()?, true) + .rewrite(&self.get_context(), self.shape())?; let width = self.block_indent.width() + fn_str.len() + res.len() + 5; if !res.contains('\n') && width <= self.config.max_width() { @@ -427,19 +385,22 @@ fn single_line_fn( } } - pub fn visit_static(&mut self, static_parts: &StaticParts<'_>) { + pub(crate) fn visit_static(&mut self, static_parts: &StaticParts<'_>) { let rewrite = rewrite_static(&self.get_context(), static_parts, self.block_indent); self.push_rewrite(static_parts.span, rewrite); } - pub fn visit_struct(&mut self, struct_parts: &StructParts<'_>) { - let is_tuple = struct_parts.def.is_tuple(); + pub(crate) fn visit_struct(&mut self, struct_parts: &StructParts<'_>) { + let is_tuple = match struct_parts.def { + ast::VariantData::Tuple(..) => true, + _ => false, + }; let rewrite = format_struct(&self.get_context(), struct_parts, self.block_indent, None) .map(|s| if is_tuple { s + ";" } else { s }); self.push_rewrite(struct_parts.span, rewrite); } - pub fn visit_enum( + pub(crate) fn visit_enum( &mut self, ident: ast::Ident, vis: &ast::Visibility, @@ -512,8 +473,8 @@ fn format_variant_list( let discr_ident_lens: Vec = enum_def .variants .iter() - .filter(|var| var.node.disr_expr.is_some()) - .map(|var| rewrite_ident(&self.get_context(), var.node.ident).len()) + .filter(|var| var.disr_expr.is_some()) + .map(|var| rewrite_ident(&self.get_context(), var.ident).len()) .collect(); // cut the list at the point of longest discrim shorter than the threshold // All of the discrims under the threshold will get padded, and all above - left as is. @@ -530,8 +491,8 @@ fn format_variant_list( "}", ",", |f| { - if !f.node.attrs.is_empty() { - f.node.attrs[0].span.lo() + if !f.attrs.is_empty() { + f.attrs[0].span.lo() } else { f.span.lo() } @@ -572,8 +533,8 @@ fn format_variant( one_line_width: usize, pad_discrim_ident_to: usize, ) -> Option { - if contains_skip(&field.node.attrs) { - let lo = field.node.attrs[0].span.lo(); + if contains_skip(&field.attrs) { + let lo = field.attrs[0].span.lo(); let span = mk_sp(lo, field.span.hi()); return Some(self.snippet(span).to_owned()); } @@ -581,33 +542,34 @@ fn format_variant( let context = self.get_context(); // 1 = ',' let shape = self.shape().sub_width(1)?; - let attrs_str = field.node.attrs.rewrite(&context, shape)?; + let attrs_str = field.attrs.rewrite(&context, shape)?; let lo = field - .node .attrs .last() .map_or(field.span.lo(), |attr| attr.span.hi()); let span = mk_sp(lo, field.span.lo()); - let variant_body = match field.node.data { + let variant_body = match field.data { ast::VariantData::Tuple(..) | ast::VariantData::Struct(..) => format_struct( &context, &StructParts::from_variant(field), self.block_indent, Some(one_line_width), )?, - ast::VariantData::Unit(..) => { - if let Some(ref expr) = field.node.disr_expr { - let lhs = format!( - "{:1$} =", - rewrite_ident(&context, field.node.ident), - pad_discrim_ident_to - ); - rewrite_assign_rhs(&context, lhs, &*expr.value, shape)? - } else { - rewrite_ident(&context, field.node.ident).to_owned() - } - } + ast::VariantData::Unit(..) => rewrite_ident(&context, field.ident).to_owned(), + }; + + let variant_body = if let Some(ref expr) = field.disr_expr { + let lhs = format!("{:1$} =", variant_body, pad_discrim_ident_to); + rewrite_assign_rhs_with( + &context, + lhs, + &*expr.value, + shape, + RhsTactics::AllowOverflow, + )? + } else { + variant_body }; combine_strs_with_missing_comments(&context, &attrs_str, &variant_body, span, shape, false) @@ -622,27 +584,27 @@ fn visit_impl_items(&mut self, items: &[ast::ImplItem]) { buffer.push((self.buffer.clone(), item.clone())); self.buffer.clear(); } - // type -> existential -> const -> macro -> method + // type -> opaque -> const -> macro -> method use crate::ast::ImplItemKind::*; fn need_empty_line(a: &ast::ImplItemKind, b: &ast::ImplItemKind) -> bool { match (a, b) { - (Type(..), Type(..)) + (TyAlias(..), TyAlias(..)) | (Const(..), Const(..)) - | (Existential(..), Existential(..)) => false, + | (OpaqueTy(..), OpaqueTy(..)) => false, _ => true, } } - buffer.sort_by(|(_, a), (_, b)| match (&a.node, &b.node) { - (Type(..), Type(..)) + buffer.sort_by(|(_, a), (_, b)| match (&a.kind, &b.kind) { + (TyAlias(..), TyAlias(..)) | (Const(..), Const(..)) | (Macro(..), Macro(..)) - | (Existential(..), Existential(..)) => a.ident.as_str().cmp(&b.ident.as_str()), + | (OpaqueTy(..), OpaqueTy(..)) => a.ident.as_str().cmp(&b.ident.as_str()), (Method(..), Method(..)) => a.span.lo().cmp(&b.span.lo()), - (Type(..), _) => Ordering::Less, - (_, Type(..)) => Ordering::Greater, - (Existential(..), _) => Ordering::Less, - (_, Existential(..)) => Ordering::Greater, + (TyAlias(..), _) => Ordering::Less, + (_, TyAlias(..)) => Ordering::Greater, + (OpaqueTy(..), _) => Ordering::Less, + (_, OpaqueTy(..)) => Ordering::Greater, (Const(..), _) => Ordering::Less, (_, Const(..)) => Ordering::Greater, (Macro(..), _) => Ordering::Less, @@ -654,14 +616,14 @@ fn need_empty_line(a: &ast::ImplItemKind, b: &ast::ImplItemKind) -> bool { // different impl items. if prev_kind .as_ref() - .map_or(false, |prev_kind| need_empty_line(prev_kind, &item.node)) + .map_or(false, |prev_kind| need_empty_line(prev_kind, &item.kind)) { self.push_str("\n"); } let indent_str = self.block_indent.to_string_with_newline(self.config); self.push_str(&indent_str); self.push_str(buf.trim()); - prev_kind = Some(item.node.clone()); + prev_kind = Some(item.kind.clone()); } } else { for item in items { @@ -671,13 +633,12 @@ fn need_empty_line(a: &ast::ImplItemKind, b: &ast::ImplItemKind) -> bool { } } -pub fn format_impl( +pub(crate) fn format_impl( context: &RewriteContext<'_>, item: &ast::Item, offset: Indent, - where_span_end: Option, ) -> Option { - if let ast::ItemKind::Impl(_, _, _, ref generics, _, ref self_ty, ref items) = item.node { + if let ast::ItemKind::Impl(_, _, _, ref generics, _, ref self_ty, ref items) = item.kind { let mut result = String::with_capacity(128); let ref_and_type = format_impl_ref_and_type(context, item, offset)?; let sep = offset.to_string_with_newline(context.config); @@ -699,23 +660,24 @@ pub fn format_impl( { option.suppress_comma(); option.snuggle(); - option.compress_where(); + option.allow_single_line(); } + let missing_span = mk_sp(self_ty.span.hi(), item.span.hi()); + let where_span_end = context.snippet_provider.opt_span_before(missing_span, "{"); let where_clause_str = rewrite_where_clause( context, &generics.where_clause, context.config.brace_style(), Shape::legacy(where_budget, offset.block_only()), - Density::Vertical, + false, "{", where_span_end, self_ty.span.hi(), option, - false, )?; - // If there is no where clause, we may have missing comments between the trait name and + // If there is no where-clause, we may have missing comments between the trait name and // the opening brace. if generics.where_clause.predicates.is_empty() { if let Some(hi) = where_span_end { @@ -737,12 +699,12 @@ pub fn format_impl( result.push_str(&where_clause_str); if where_clause_str.contains('\n') || last_line_contains_single_line_comment(&result) { // if the where_clause contains extra comments AND - // there is only one where clause predicate + // there is only one where-clause predicate // recover the suppressed comma in single line where_clause formatting if generics.where_clause.predicates.len() == 1 { result.push_str(","); } - result.push_str(&format!("{}{{{}}}", &sep, &sep)); + result.push_str(&format!("{}{{{}}}", sep, sep)); } else { result.push_str(" {}"); } @@ -766,15 +728,16 @@ pub fn format_impl( } result.push('{'); - - let snippet = context.snippet(item.span); + // this is an impl body snippet(impl SampleImpl { /* here */ }) + let lo = max(self_ty.span.hi(), generics.where_clause.span.hi()); + let snippet = context.snippet(mk_sp(lo, item.span.hi())); let open_pos = snippet.find_uncommented("{")? + 1; if !items.is_empty() || contains_comment(&snippet[open_pos..]) { let mut visitor = FmtVisitor::from_context(context); let item_indent = offset.block_only().block_indent(context.config); visitor.block_indent = item_indent; - visitor.last_pos = item.span.lo() + BytePos(open_pos as u32); + visitor.last_pos = lo + BytePos(open_pos as u32); visitor.visit_attrs(&item.attrs, ast::AttrStyle::Inner); visitor.visit_impl_items(items); @@ -831,7 +794,7 @@ fn format_impl_ref_and_type( ref trait_ref, ref self_ty, _, - ) = item.node + ) = item.kind { let mut result = String::with_capacity(128); @@ -868,7 +831,7 @@ fn format_impl_ref_and_type( // ` for` let trait_ref_overhead = if trait_ref.is_some() { 4 } else { 0 }; let curly_brace_overhead = if generics.where_clause.predicates.is_empty() { - // If there is no where clause adapt budget for type formatting to take space and curly + // If there is no where-clause adapt budget for type formatting to take space and curly // brace into account. match context.config.brace_style() { BraceStyle::AlwaysNextLine => 0, @@ -924,7 +887,7 @@ fn rewrite_trait_ref( let shape = Shape::indented(offset + used_space, context.config); if let Some(trait_ref_str) = trait_ref.rewrite(context, shape) { if !trait_ref_str.contains('\n') { - return Some(format!(" {}{}", polarity_str, &trait_ref_str)); + return Some(format!(" {}{}", polarity_str, trait_ref_str)); } } // We could not make enough space for trait_ref, so put it on new line. @@ -933,13 +896,13 @@ fn rewrite_trait_ref( let trait_ref_str = trait_ref.rewrite(context, shape)?; Some(format!( "{}{}{}", - &offset.to_string_with_newline(context.config), + offset.to_string_with_newline(context.config), polarity_str, - &trait_ref_str + trait_ref_str )) } -pub struct StructParts<'a> { +pub(crate) struct StructParts<'a> { prefix: &'a str, ident: ast::Ident, vis: &'a ast::Visibility, @@ -956,16 +919,16 @@ fn format_header(&self, context: &RewriteContext<'_>) -> String { fn from_variant(variant: &'a ast::Variant) -> Self { StructParts { prefix: "", - ident: variant.node.ident, + ident: variant.ident, vis: &DEFAULT_VISIBILITY, - def: &variant.node.data, + def: &variant.data, generics: None, span: variant.span, } } - pub fn from_item(item: &'a ast::Item) -> Self { - let (prefix, def, generics) = match item.node { + pub(crate) fn from_item(item: &'a ast::Item) -> Self { + let (prefix, def, generics) = match item.kind { ast::ItemKind::Struct(ref def, ref generics) => ("struct ", def, generics), ast::ItemKind::Union(ref def, ref generics) => ("union ", def, generics), _ => unreachable!(), @@ -998,14 +961,18 @@ fn format_struct( } } -pub fn format_trait(context: &RewriteContext<'_>, item: &ast::Item, offset: Indent) -> Option { +pub(crate) fn format_trait( + context: &RewriteContext<'_>, + item: &ast::Item, + offset: Indent, +) -> Option { if let ast::ItemKind::Trait( is_auto, unsafety, ref generics, ref generic_bounds, ref trait_items, - ) = item.node + ) = item.kind { let mut result = String::with_capacity(128); let header = format!( @@ -1043,13 +1010,9 @@ pub fn format_trait(context: &RewriteContext<'_>, item: &ast::Item, offset: Inde )?; } - // Rewrite where clause. + // Rewrite where-clause. if !generics.where_clause.predicates.is_empty() { - let where_density = if context.config.indent_style() == IndentStyle::Block { - Density::Compressed - } else { - Density::Tall - }; + let where_on_new_line = context.config.indent_style() != IndentStyle::Block; let where_budget = context.budget(last_line_width(&result)); let pos_before_where = if generic_bounds.is_empty() { @@ -1063,15 +1026,14 @@ pub fn format_trait(context: &RewriteContext<'_>, item: &ast::Item, offset: Inde &generics.where_clause, context.config.brace_style(), Shape::legacy(where_budget, offset.block_only()), - where_density, + where_on_new_line, "{", None, pos_before_where, option, - false, )?; - // If the where clause cannot fit on the same line, - // put the where clause on a new line + // If the where-clause cannot fit on the same line, + // put the where-clause on a new line if !where_clause_str.contains('\n') && last_line_width(&result) + where_clause_str.len() + offset.width() > context.config.comment_width() @@ -1156,9 +1118,61 @@ pub fn format_trait(context: &RewriteContext<'_>, item: &ast::Item, offset: Inde } } -pub fn format_trait_alias( +struct OpaqueTypeBounds<'a> { + generic_bounds: &'a ast::GenericBounds, +} + +impl<'a> Rewrite for OpaqueTypeBounds<'a> { + fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option { + self.generic_bounds + .rewrite(context, shape) + .map(|s| format!("impl {}", s)) + } +} + +pub(crate) struct TraitAliasBounds<'a> { + generic_bounds: &'a ast::GenericBounds, + generics: &'a ast::Generics, +} + +impl<'a> Rewrite for TraitAliasBounds<'a> { + fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option { + let generic_bounds_str = self.generic_bounds.rewrite(context, shape)?; + + let mut option = WhereClauseOption::new(true, WhereClauseSpace::None); + option.allow_single_line(); + + let where_str = rewrite_where_clause( + context, + &self.generics.where_clause, + context.config.brace_style(), + shape, + false, + ";", + None, + self.generics.where_clause.span.lo(), + option, + )?; + + let fits_single_line = !generic_bounds_str.contains('\n') + && !where_str.contains('\n') + && generic_bounds_str.len() + where_str.len() + 1 <= shape.width; + let space = if generic_bounds_str.is_empty() || where_str.is_empty() { + Cow::from("") + } else if fits_single_line { + Cow::from(" ") + } else { + shape.indent.to_string_with_newline(&context.config) + }; + + Some(format!("{}{}{}", generic_bounds_str, space, where_str)) + } +} + +pub(crate) fn format_trait_alias( context: &RewriteContext<'_>, ident: ast::Ident, + vis: &ast::Visibility, generics: &ast::Generics, generic_bounds: &ast::GenericBounds, shape: Shape, @@ -1167,19 +1181,24 @@ pub fn format_trait_alias( // 6 = "trait ", 2 = " =" let g_shape = shape.offset_left(6)?.sub_width(2)?; let generics_str = rewrite_generics(context, &alias, generics, g_shape)?; - let lhs = format!("trait {} =", generics_str); + let vis_str = format_visibility(context, vis); + let lhs = format!("{}trait {} =", vis_str, generics_str); // 1 = ";" - rewrite_assign_rhs(context, lhs, generic_bounds, shape.sub_width(1)?).map(|s| s + ";") + let trait_alias_bounds = TraitAliasBounds { + generics, + generic_bounds, + }; + rewrite_assign_rhs(context, lhs, &trait_alias_bounds, shape.sub_width(1)?).map(|s| s + ";") } -fn format_unit_struct(context: &RewriteContext<'_>, p: &StructParts<'_>, offset: Indent) -> Option { +fn format_unit_struct( + context: &RewriteContext<'_>, + p: &StructParts<'_>, + offset: Indent, +) -> Option { let header_str = format_header(context, p.prefix, p.ident, p.vis); let generics_str = if let Some(generics) = p.generics { - let hi = if generics.where_clause.predicates.is_empty() { - generics.span.hi() - } else { - generics.where_clause.span.hi() - }; + let hi = context.snippet_provider.span_before(p.span, ";"); format_generics( context, generics, @@ -1196,7 +1215,7 @@ fn format_unit_struct(context: &RewriteContext<'_>, p: &StructParts<'_>, offset: Some(format!("{}{};", header_str, generics_str)) } -pub fn format_struct_struct( +pub(crate) fn format_struct_struct( context: &RewriteContext<'_>, struct_parts: &StructParts<'_>, fields: &[ast::StructField], @@ -1363,7 +1382,7 @@ fn format_tuple_struct( context .snippet_provider .opt_span_after(mk_sp(last_arg_span.hi(), span.hi()), ")") - .unwrap_or(last_arg_span.hi()) + .unwrap_or_else(|| last_arg_span.hi()) }; let where_clause_str = match struct_parts.generics { @@ -1374,18 +1393,17 @@ fn format_tuple_struct( result.push_str(&generics_str); let where_budget = context.budget(last_line_width(&result)); - let option = WhereClauseOption::new(true, false); + let option = WhereClauseOption::new(true, WhereClauseSpace::Newline); rewrite_where_clause( context, &generics.where_clause, context.config.brace_style(), Shape::legacy(where_budget, offset.block_only()), - Density::Compressed, + false, ";", None, body_hi, option, - false, )? } None => "".to_owned(), @@ -1416,8 +1434,8 @@ fn format_tuple_struct( || offset.block_indent + result.len() + where_clause_str.len() + 1 > context.config.max_width()) { - // We need to put the where clause on a new line, but we didn't - // know that earlier, so the where clause will not be indented properly. + // We need to put the where-clause on a new line, but we didn't + // know that earlier, so the where-clause will not be indented properly. result.push('\n'); result.push_str( &(offset.block_only() + (context.config.tab_spaces() - 1)).to_string(context.config), @@ -1457,12 +1475,11 @@ fn rewrite_type_prefix( &generics.where_clause, context.config.brace_style(), Shape::legacy(where_budget, indent), - Density::Vertical, + false, "=", None, generics.span.hi(), option, - false, )?; result.push_str(&where_clause_str); @@ -1500,7 +1517,7 @@ fn rewrite_type_item( rewrite_assign_rhs(context, result, rhs, rhs_shape).map(|s| s + ";") } -pub fn rewrite_type_alias( +pub(crate) fn rewrite_type_alias( context: &RewriteContext<'_>, indent: Indent, ident: ast::Ident, @@ -1511,7 +1528,7 @@ pub fn rewrite_type_alias( rewrite_type_item(context, indent, "type", " =", ident, ty, generics, vis) } -pub fn rewrite_existential_type( +pub(crate) fn rewrite_opaque_type( context: &RewriteContext<'_>, indent: Indent, ident: ast::Ident, @@ -1519,13 +1536,14 @@ pub fn rewrite_existential_type( generics: &ast::Generics, vis: &ast::Visibility, ) -> Option { + let opaque_type_bounds = OpaqueTypeBounds { generic_bounds }; rewrite_type_item( context, indent, - "existential type", - ":", + "type", + " =", ident, - generic_bounds, + &opaque_type_bounds, generics, vis, ) @@ -1538,7 +1556,7 @@ fn type_annotation_spacing(config: &Config) -> (&str, &str) { ) } -pub fn rewrite_struct_field_prefix( +pub(crate) fn rewrite_struct_field_prefix( context: &RewriteContext<'_>, field: &ast::StructField, ) -> Option { @@ -1561,7 +1579,7 @@ fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option } } -pub fn rewrite_struct_field( +pub(crate) fn rewrite_struct_field( context: &RewriteContext<'_>, field: &ast::StructField, shape: Shape, @@ -1625,7 +1643,7 @@ pub fn rewrite_struct_field( combine_strs_with_missing_comments(context, &attrs_str, field_str, missing_span, shape, false) } -pub struct StaticParts<'a> { +pub(crate) struct StaticParts<'a> { prefix: &'a str, vis: &'a ast::Visibility, ident: ast::Ident, @@ -1637,8 +1655,8 @@ pub struct StaticParts<'a> { } impl<'a> StaticParts<'a> { - pub fn from_item(item: &'a ast::Item) -> Self { - let (prefix, ty, mutability, expr) = match item.node { + pub(crate) fn from_item(item: &'a ast::Item) -> Self { + let (prefix, ty, mutability, expr) = match item.kind { ast::ItemKind::Static(ref ty, mutability, ref expr) => ("static", ty, mutability, expr), ast::ItemKind::Const(ref ty, ref expr) => { ("const", ty, ast::Mutability::Immutable, expr) @@ -1657,8 +1675,8 @@ pub fn from_item(item: &'a ast::Item) -> Self { } } - pub fn from_trait_item(ti: &'a ast::TraitItem) -> Self { - let (ty, expr_opt) = match ti.node { + pub(crate) fn from_trait_item(ti: &'a ast::TraitItem) -> Self { + let (ty, expr_opt) = match ti.kind { ast::TraitItemKind::Const(ref ty, ref expr_opt) => (ty, expr_opt), _ => unreachable!(), }; @@ -1674,8 +1692,8 @@ pub fn from_trait_item(ti: &'a ast::TraitItem) -> Self { } } - pub fn from_impl_item(ii: &'a ast::ImplItem) -> Self { - let (ty, expr) = match ii.node { + pub(crate) fn from_impl_item(ii: &'a ast::ImplItem) -> Self { + let (ty, expr) = match ii.kind { ast::ImplItemKind::Const(ref ty, ref expr) => (ty, expr), _ => unreachable!(), }; @@ -1697,10 +1715,7 @@ fn rewrite_static( static_parts: &StaticParts<'_>, offset: Indent, ) -> Option { - let colon = colon_spaces( - context.config.space_before_colon(), - context.config.space_after_colon(), - ); + let colon = colon_spaces(context.config); let mut prefix = format!( "{}{}{} {}{}{}", format_visibility(context, static_parts.vis), @@ -1747,7 +1762,7 @@ fn rewrite_static( } } -pub fn rewrite_associated_type( +pub(crate) fn rewrite_associated_type( ident: ast::Ident, ty_opt: Option<&ptr::P>, generics: &ast::Generics, @@ -1783,18 +1798,45 @@ pub fn rewrite_associated_type( } } -pub fn rewrite_existential_impl_type( +struct OpaqueType<'a> { + bounds: &'a ast::GenericBounds, +} + +impl<'a> Rewrite for OpaqueType<'a> { + fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option { + let shape = shape.offset_left(5)?; // `impl ` + self.bounds + .rewrite(context, shape) + .map(|s| format!("impl {}", s)) + } +} + +pub(crate) fn rewrite_opaque_impl_type( context: &RewriteContext<'_>, ident: ast::Ident, generics: &ast::Generics, generic_bounds: &ast::GenericBounds, indent: Indent, ) -> Option { - rewrite_associated_type(ident, None, generics, Some(generic_bounds), context, indent) - .map(|s| format!("existential {}", s)) + let ident_str = rewrite_ident(context, ident); + // 5 = "type " + let generics_shape = Shape::indented(indent, context.config).offset_left(5)?; + let generics_str = rewrite_generics(context, ident_str, generics, generics_shape)?; + let prefix = format!("type {} =", generics_str); + let rhs = OpaqueType { + bounds: generic_bounds, + }; + + rewrite_assign_rhs( + context, + &prefix, + &rhs, + Shape::indented(indent, context.config).sub_width(1)?, + ) + .map(|s| s + ";") } -pub fn rewrite_associated_impl_type( +pub(crate) fn rewrite_associated_impl_type( ident: ast::Ident, defaultness: ast::Defaultness, ty_opt: Option<&ptr::P>, @@ -1815,36 +1857,107 @@ fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option match *self { ast::FunctionRetTy::Default(_) => Some(String::new()), ast::FunctionRetTy::Ty(ref ty) => { - let inner_width = shape.width.checked_sub(3)?; - ty.rewrite(context, Shape::legacy(inner_width, shape.indent + 3)) - .map(|r| format!("-> {}", r)) + if context.config.version() == Version::One + || context.config.indent_style() == IndentStyle::Visual + { + let inner_width = shape.width.checked_sub(3)?; + return ty + .rewrite(context, Shape::legacy(inner_width, shape.indent + 3)) + .map(|r| format!("-> {}", r)); + } + + ty.rewrite(context, shape.offset_left(3)?) + .map(|s| format!("-> {}", s)) } } } } fn is_empty_infer(ty: &ast::Ty, pat_span: Span) -> bool { - match ty.node { + match ty.kind { ast::TyKind::Infer => ty.span.hi() == pat_span.hi(), _ => false, } } -impl Rewrite for ast::Arg { +/// Recover any missing comments between the param and the type. +/// +/// # Returns +/// +/// A 2-len tuple with the comment before the colon in first position, and the comment after the +/// colon in second position. +fn get_missing_param_comments( + context: &RewriteContext<'_>, + pat_span: Span, + ty_span: Span, + shape: Shape, +) -> (String, String) { + let missing_comment_span = mk_sp(pat_span.hi(), ty_span.lo()); + + let span_before_colon = { + let missing_comment_span_hi = context + .snippet_provider + .span_before(missing_comment_span, ":"); + mk_sp(pat_span.hi(), missing_comment_span_hi) + }; + let span_after_colon = { + let missing_comment_span_lo = context + .snippet_provider + .span_after(missing_comment_span, ":"); + mk_sp(missing_comment_span_lo, ty_span.lo()) + }; + + let comment_before_colon = rewrite_missing_comment(span_before_colon, shape, context) + .filter(|comment| !comment.is_empty()) + .map_or(String::new(), |comment| format!(" {}", comment)); + let comment_after_colon = rewrite_missing_comment(span_after_colon, shape, context) + .filter(|comment| !comment.is_empty()) + .map_or(String::new(), |comment| format!("{} ", comment)); + (comment_before_colon, comment_after_colon) +} + +impl Rewrite for ast::Param { fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option { - if is_named_arg(self) { - let mut result = self - .pat - .rewrite(context, Shape::legacy(shape.width, shape.indent))?; + let param_attrs_result = self + .attrs + .rewrite(context, Shape::legacy(shape.width, shape.indent))?; + let (span, has_multiple_attr_lines) = if !self.attrs.is_empty() { + let num_attrs = self.attrs.len(); + ( + mk_sp(self.attrs[num_attrs - 1].span.hi(), self.pat.span.lo()), + param_attrs_result.contains("\n"), + ) + } else { + (mk_sp(self.span.lo(), self.span.lo()), false) + }; + + if let Some(ref explicit_self) = self.to_self() { + rewrite_explicit_self( + context, + explicit_self, + ¶m_attrs_result, + span, + shape, + has_multiple_attr_lines, + ) + } else if is_named_param(self) { + let mut result = combine_strs_with_missing_comments( + context, + ¶m_attrs_result, + &self + .pat + .rewrite(context, Shape::legacy(shape.width, shape.indent))?, + span, + shape, + !has_multiple_attr_lines, + )?; if !is_empty_infer(&*self.ty, self.pat.span) { - if context.config.space_before_colon() { - result.push_str(" "); - } - result.push_str(":"); - if context.config.space_after_colon() { - result.push_str(" "); - } + let (before_comment, after_comment) = + get_missing_param_comments(context, self.pat.span, self.ty.span, shape); + result.push_str(&before_comment); + result.push_str(colon_spaces(context.config)); + result.push_str(&after_comment); let overhead = last_line_width(&result); let max_width = shape.width.checked_sub(overhead)?; let ty_str = self @@ -1861,9 +1974,12 @@ fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option } fn rewrite_explicit_self( - explicit_self: &ast::ExplicitSelf, - args: &[ast::Arg], context: &RewriteContext<'_>, + explicit_self: &ast::ExplicitSelf, + param_attrs: &str, + span: Span, + shape: Shape, + has_multiple_attr_lines: bool, ) -> Option { match explicit_self.node { ast::SelfKind::Region(lt, m) => { @@ -1874,70 +1990,86 @@ fn rewrite_explicit_self( context, Shape::legacy(context.config.max_width(), Indent::empty()), )?; - Some(format!("&{} {}self", lifetime_str, mut_str)) + Some(combine_strs_with_missing_comments( + context, + ¶m_attrs, + &format!("&{} {}self", lifetime_str, mut_str), + span, + shape, + !has_multiple_attr_lines, + )?) } - None => Some(format!("&{}self", mut_str)), + None => Some(combine_strs_with_missing_comments( + context, + ¶m_attrs, + &format!("&{}self", mut_str), + span, + shape, + !has_multiple_attr_lines, + )?), } } - ast::SelfKind::Explicit(ref ty, _) => { - assert!(!args.is_empty(), "&[ast::Arg] shouldn't be empty."); - - let mutability = explicit_self_mutability(&args[0]); + ast::SelfKind::Explicit(ref ty, mutability) => { let type_str = ty.rewrite( context, Shape::legacy(context.config.max_width(), Indent::empty()), )?; - Some(format!( - "{}self: {}", - format_mutability(mutability), - type_str - )) - } - ast::SelfKind::Value(_) => { - assert!(!args.is_empty(), "&[ast::Arg] shouldn't be empty."); - - let mutability = explicit_self_mutability(&args[0]); - - Some(format!("{}self", format_mutability(mutability))) + Some(combine_strs_with_missing_comments( + context, + ¶m_attrs, + &format!("{}self: {}", format_mutability(mutability), type_str), + span, + shape, + !has_multiple_attr_lines, + )?) } + ast::SelfKind::Value(mutability) => Some(combine_strs_with_missing_comments( + context, + ¶m_attrs, + &format!("{}self", format_mutability(mutability)), + span, + shape, + !has_multiple_attr_lines, + )?), } } -// Hacky solution caused by absence of `Mutability` in `SelfValue` and -// `SelfExplicit` variants of `ast::ExplicitSelf_`. -fn explicit_self_mutability(arg: &ast::Arg) -> ast::Mutability { - if let ast::PatKind::Ident(ast::BindingMode::ByValue(mutability), _, _) = arg.pat.node { - mutability - } else { - unreachable!() - } -} - -pub fn span_lo_for_arg(arg: &ast::Arg) -> BytePos { - if is_named_arg(arg) { - arg.pat.span.lo() +pub(crate) fn span_lo_for_param(param: &ast::Param) -> BytePos { + if param.attrs.is_empty() { + if is_named_param(param) { + param.pat.span.lo() + } else { + param.ty.span.lo() + } } else { - arg.ty.span.lo() + param.attrs[0].span.lo() } } -pub fn span_hi_for_arg(context: &RewriteContext<'_>, arg: &ast::Arg) -> BytePos { - match arg.ty.node { - ast::TyKind::Infer if context.snippet(arg.ty.span) == "_" => arg.ty.span.hi(), - ast::TyKind::Infer if is_named_arg(arg) => arg.pat.span.hi(), - _ => arg.ty.span.hi(), +pub(crate) fn span_hi_for_param(context: &RewriteContext<'_>, param: &ast::Param) -> BytePos { + match param.ty.kind { + ast::TyKind::Infer if context.snippet(param.ty.span) == "_" => param.ty.span.hi(), + ast::TyKind::Infer if is_named_param(param) => param.pat.span.hi(), + _ => param.ty.span.hi(), } } -pub fn is_named_arg(arg: &ast::Arg) -> bool { - if let ast::PatKind::Ident(_, ident, _) = arg.pat.node { - ident != symbol::keywords::Invalid.ident() +pub(crate) fn is_named_param(param: &ast::Param) -> bool { + if let ast::PatKind::Ident(_, ident, _) = param.pat.kind { + ident.name != symbol::kw::Invalid } else { true } } +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub(crate) enum FnBraceStyle { + SameLine, + NextLine, + None, +} + // Return type is (result, force_new_line_for_brace) fn rewrite_fn_base( context: &RewriteContext<'_>, @@ -1945,8 +2077,7 @@ fn rewrite_fn_base( ident: ast::Ident, fn_sig: &FnSig<'_>, span: Span, - newline_brace: bool, - has_body: bool, + fn_brace_style: FnBraceStyle, ) -> Option<(String, bool)> { let mut force_new_line_for_brace = false; @@ -1959,7 +2090,7 @@ fn rewrite_fn_base( result.push_str("fn "); // Generics. - let overhead = if has_body && !newline_brace { + let overhead = if let FnBraceStyle::SameLine = fn_brace_style { // 4 = `() {` 4 } else { @@ -1996,20 +2127,19 @@ fn rewrite_fn_base( let multi_line_ret_str = ret_str.contains('\n'); let ret_str_len = if multi_line_ret_str { 0 } else { ret_str.len() }; - // Args. - let (one_line_budget, multi_line_budget, mut arg_indent) = compute_budgets_for_args( + // Params. + let (one_line_budget, multi_line_budget, mut param_indent) = compute_budgets_for_params( context, &result, indent, ret_str_len, - newline_brace, - has_body, + fn_brace_style, multi_line_ret_str, )?; debug!( - "rewrite_fn_base: one_line_budget: {}, multi_line_budget: {}, arg_indent: {:?}", - one_line_budget, multi_line_budget, arg_indent + "rewrite_fn_base: one_line_budget: {}, multi_line_budget: {}, param_indent: {:?}", + one_line_budget, multi_line_budget, param_indent ); result.push('('); @@ -2018,81 +2148,79 @@ fn rewrite_fn_base( && !snuggle_angle_bracket && context.config.indent_style() == IndentStyle::Visual { - result.push_str(&arg_indent.to_string_with_newline(context.config)); + result.push_str(¶m_indent.to_string_with_newline(context.config)); } // Skip `pub(crate)`. let lo_after_visibility = get_bytepos_after_visibility(&fn_sig.visibility, span); // A conservative estimation, to goal is to be over all parens in generics - let args_start = fn_sig + let params_start = fn_sig .generics .params .iter() .last() .map_or(lo_after_visibility, |param| param.span().hi()); - let args_end = if fd.inputs.is_empty() { + let params_end = if fd.inputs.is_empty() { context .snippet_provider - .span_after(mk_sp(args_start, span.hi()), ")") + .span_after(mk_sp(params_start, span.hi()), ")") } else { let last_span = mk_sp(fd.inputs[fd.inputs.len() - 1].span().hi(), span.hi()); context.snippet_provider.span_after(last_span, ")") }; - let args_span = mk_sp( + let params_span = mk_sp( context .snippet_provider - .span_after(mk_sp(args_start, span.hi()), "("), - args_end, + .span_after(mk_sp(params_start, span.hi()), "("), + params_end, ); - let arg_str = rewrite_args( + let param_str = rewrite_params( context, &fd.inputs, - fd.get_self().as_ref(), one_line_budget, multi_line_budget, indent, - arg_indent, - args_span, - fd.variadic, - generics_str.contains('\n'), + param_indent, + params_span, + fd.c_variadic(), )?; - let put_args_in_block = match context.config.indent_style() { - IndentStyle::Block => arg_str.contains('\n') || arg_str.len() > one_line_budget, + let put_params_in_block = match context.config.indent_style() { + IndentStyle::Block => param_str.contains('\n') || param_str.len() > one_line_budget, _ => false, } && !fd.inputs.is_empty(); - let mut args_last_line_contains_comment = false; - let mut no_args_and_over_max_width = false; + let mut params_last_line_contains_comment = false; + let mut no_params_and_over_max_width = false; - if put_args_in_block { - arg_indent = indent.block_indent(context.config); - result.push_str(&arg_indent.to_string_with_newline(context.config)); - result.push_str(&arg_str); + if put_params_in_block { + param_indent = indent.block_indent(context.config); + result.push_str(¶m_indent.to_string_with_newline(context.config)); + result.push_str(¶m_str); result.push_str(&indent.to_string_with_newline(context.config)); result.push(')'); } else { - result.push_str(&arg_str); + result.push_str(¶m_str); let used_width = last_line_used_width(&result, indent.width()) + first_line_width(&ret_str); // Put the closing brace on the next line if it overflows the max width. // 1 = `)` let closing_paren_overflow_max_width = fd.inputs.is_empty() && used_width + 1 > context.config.max_width(); - // If the last line of args contains comment, we cannot put the closing paren + // If the last line of params contains comment, we cannot put the closing paren // on the same line. - args_last_line_contains_comment = arg_str + params_last_line_contains_comment = param_str .lines() .last() .map_or(false, |last_line| last_line.contains("//")); if context.config.version() == Version::Two { result.push(')'); - if closing_paren_overflow_max_width || args_last_line_contains_comment { + if closing_paren_overflow_max_width || params_last_line_contains_comment { result.push_str(&indent.to_string_with_newline(context.config)); - no_args_and_over_max_width = true; + no_params_and_over_max_width = true; } } else { - if closing_paren_overflow_max_width || args_last_line_contains_comment { + if closing_paren_overflow_max_width || params_last_line_contains_comment { result.push_str(&indent.to_string_with_newline(context.config)); } result.push(')'); @@ -2102,17 +2230,17 @@ fn rewrite_fn_base( // Return type. if let ast::FunctionRetTy::Ty(..) = fd.output { let ret_should_indent = match context.config.indent_style() { - // If our args are block layout then we surely must have space. - IndentStyle::Block if put_args_in_block || fd.inputs.is_empty() => false, - _ if args_last_line_contains_comment => false, + // If our params are block layout then we surely must have space. + IndentStyle::Block if put_params_in_block || fd.inputs.is_empty() => false, + _ if params_last_line_contains_comment => false, _ if result.contains('\n') || multi_line_ret_str => true, _ => { // If the return type would push over the max width, then put the return type on // a new line. With the +1 for the signature length an additional space between - // the closing parenthesis of the argument and the arrow '->' is considered. + // the closing parenthesis of the param and the arrow '->' is considered. let mut sig_length = result.len() + indent.width() + ret_str_len + 1; - // If there is no where clause, take into account the space after the return type + // If there is no where-clause, take into account the space after the return type // and the brace. if where_clause.predicates.is_empty() { sig_length += 2; @@ -2121,38 +2249,58 @@ fn rewrite_fn_base( sig_length > context.config.max_width() } }; - let ret_indent = if ret_should_indent { - let indent = if arg_str.is_empty() { - // Aligning with non-existent args looks silly. - force_new_line_for_brace = true; - indent + 4 + let ret_shape = if ret_should_indent { + if context.config.version() == Version::One + || context.config.indent_style() == IndentStyle::Visual + { + let indent = if param_str.is_empty() { + // Aligning with non-existent params looks silly. + force_new_line_for_brace = true; + indent + 4 + } else { + // FIXME: we might want to check that using the param indent + // doesn't blow our budget, and if it does, then fallback to + // the where-clause indent. + param_indent + }; + + result.push_str(&indent.to_string_with_newline(context.config)); + Shape::indented(indent, context.config) } else { - // FIXME: we might want to check that using the arg indent - // doesn't blow our budget, and if it does, then fallback to - // the where clause indent. - arg_indent - }; + let mut ret_shape = Shape::indented(indent, context.config); + if param_str.is_empty() { + // Aligning with non-existent params looks silly. + force_new_line_for_brace = true; + ret_shape = if context.use_block_indent() { + ret_shape.offset_left(4).unwrap_or(ret_shape) + } else { + ret_shape.indent = ret_shape.indent + 4; + ret_shape + }; + } - result.push_str(&indent.to_string_with_newline(context.config)); - indent + result.push_str(&ret_shape.indent.to_string_with_newline(context.config)); + ret_shape + } } else { if context.config.version() == Version::Two { - if arg_str.len() != 0 || !no_args_and_over_max_width { + if !param_str.is_empty() || !no_params_and_over_max_width { result.push(' '); } } else { result.push(' '); } - Indent::new(indent.block_indent, last_line_width(&result)) + let ret_shape = Shape::indented(indent, context.config); + ret_shape + .offset_left(last_line_width(&result)) + .unwrap_or(ret_shape) }; if multi_line_ret_str || ret_should_indent { // Now that we know the proper indent and width, we need to // re-layout the return type. - let ret_str = fd - .output - .rewrite(context, Shape::indented(ret_indent, context.config))?; + let ret_str = fd.output.rewrite(context, ret_shape)?; result.push_str(&ret_str); } else { result.push_str(&ret_str); @@ -2186,31 +2334,38 @@ fn rewrite_fn_base( } let pos_before_where = match fd.output { - ast::FunctionRetTy::Default(..) => args_span.hi(), + ast::FunctionRetTy::Default(..) => params_span.hi(), ast::FunctionRetTy::Ty(ref ty) => ty.span.hi(), }; - let is_args_multi_lined = arg_str.contains('\n'); + let is_params_multi_lined = param_str.contains('\n'); - let option = WhereClauseOption::new(!has_body, put_args_in_block && ret_str.is_empty()); + let space = if put_params_in_block && ret_str.is_empty() { + WhereClauseSpace::Space + } else { + WhereClauseSpace::Newline + }; + let mut option = WhereClauseOption::new(fn_brace_style == FnBraceStyle::None, space); + if is_params_multi_lined { + option.veto_single_line(); + } let where_clause_str = rewrite_where_clause( context, where_clause, context.config.brace_style(), Shape::indented(indent, context.config), - Density::Tall, + true, "{", Some(span.hi()), pos_before_where, option, - is_args_multi_lined, )?; - // If there are neither where clause nor return type, we may be missing comments between - // args and `{`. + // If there are neither where-clause nor return type, we may be missing comments between + // params and `{`. if where_clause_str.is_empty() { if let ast::FunctionRetTy::Default(ret_span) = fd.output { match recover_missing_comment_in_span( - mk_sp(args_span.hi(), ret_span.hi()), + mk_sp(params_span.hi(), ret_span.hi()), shape, context, last_line_width(&result), @@ -2227,174 +2382,113 @@ fn rewrite_fn_base( result.push_str(&where_clause_str); force_new_line_for_brace |= last_line_contains_single_line_comment(&result); - force_new_line_for_brace |= is_args_multi_lined && context.config.where_single_line(); + force_new_line_for_brace |= is_params_multi_lined && context.config.where_single_line(); Some((result, force_new_line_for_brace)) } +/// Kind of spaces to put before `where`. +#[derive(Copy, Clone)] +enum WhereClauseSpace { + /// A single space. + Space, + /// A new line. + Newline, + /// Nothing. + None, +} + #[derive(Copy, Clone)] struct WhereClauseOption { suppress_comma: bool, // Force no trailing comma - snuggle: bool, // Do not insert newline before `where` - compress_where: bool, // Try single line where clause instead of vertical layout + snuggle: WhereClauseSpace, + allow_single_line: bool, // Try single line where-clause instead of vertical layout + veto_single_line: bool, // Disallow a single-line where-clause. } impl WhereClauseOption { - pub fn new(suppress_comma: bool, snuggle: bool) -> WhereClauseOption { + fn new(suppress_comma: bool, snuggle: WhereClauseSpace) -> WhereClauseOption { WhereClauseOption { suppress_comma, snuggle, - compress_where: false, + allow_single_line: false, + veto_single_line: false, } } - pub fn snuggled(current: &str) -> WhereClauseOption { + fn snuggled(current: &str) -> WhereClauseOption { WhereClauseOption { suppress_comma: false, - snuggle: last_line_width(current) == 1, - compress_where: false, + snuggle: if last_line_width(current) == 1 { + WhereClauseSpace::Space + } else { + WhereClauseSpace::Newline + }, + allow_single_line: false, + veto_single_line: false, } } - pub fn suppress_comma(&mut self) { + fn suppress_comma(&mut self) { self.suppress_comma = true } - pub fn compress_where(&mut self) { - self.compress_where = true + fn allow_single_line(&mut self) { + self.allow_single_line = true } - pub fn snuggle(&mut self) { - self.snuggle = true + fn snuggle(&mut self) { + self.snuggle = WhereClauseSpace::Space + } + + fn veto_single_line(&mut self) { + self.veto_single_line = true; } } -fn rewrite_args( +fn rewrite_params( context: &RewriteContext<'_>, - args: &[ast::Arg], - explicit_self: Option<&ast::ExplicitSelf>, + params: &[ast::Param], one_line_budget: usize, multi_line_budget: usize, indent: Indent, - arg_indent: Indent, + param_indent: Indent, span: Span, variadic: bool, - generics_str_contains_newline: bool, ) -> Option { - let mut arg_item_strs = args - .iter() - .map(|arg| { - arg.rewrite(context, Shape::legacy(multi_line_budget, arg_indent)) - .unwrap_or_else(|| context.snippet(arg.span()).to_owned()) - }) - .collect::>(); - - // Account for sugary self. - // FIXME: the comment for the self argument is dropped. This is blocked - // on rust issue #27522. - let min_args = explicit_self - .and_then(|explicit_self| rewrite_explicit_self(explicit_self, args, context)) - .map_or(1, |self_str| { - arg_item_strs[0] = self_str; - 2 - }); - - // Comments between args. - let mut arg_items = Vec::new(); - if min_args == 2 { - arg_items.push(ListItem::from_str("")); - } - - // FIXME(#21): if there are no args, there might still be a comment, but - // without spans for the comment or parens, there is no chance of - // getting it right. You also don't get to put a comment on self, unless - // it is explicit. - if args.len() >= min_args || variadic { - let comment_span_start = if min_args == 2 { - let second_arg_start = if arg_has_pattern(&args[1]) { - args[1].pat.span.lo() - } else { - args[1].ty.span.lo() - }; - let reduced_span = mk_sp(span.lo(), second_arg_start); - - context.snippet_provider.span_after_last(reduced_span, ",") - } else { - span.lo() - }; - - enum ArgumentKind<'a> { - Regular(&'a ast::Arg), - Variadic(BytePos), - } - - let variadic_arg = if variadic { - let variadic_span = mk_sp(args.last().unwrap().ty.span.hi(), span.hi()); - let variadic_start = - context.snippet_provider.span_after(variadic_span, "...") - BytePos(3); - Some(ArgumentKind::Variadic(variadic_start)) - } else { - None - }; - - let more_items = itemize_list( - context.snippet_provider, - args[min_args - 1..] - .iter() - .map(ArgumentKind::Regular) - .chain(variadic_arg), - ")", - ",", - |arg| match *arg { - ArgumentKind::Regular(arg) => span_lo_for_arg(arg), - ArgumentKind::Variadic(start) => start, - }, - |arg| match *arg { - ArgumentKind::Regular(arg) => arg.ty.span.hi(), - ArgumentKind::Variadic(start) => start + BytePos(3), - }, - |arg| match *arg { - ArgumentKind::Regular(..) => None, - ArgumentKind::Variadic(..) => Some("...".to_owned()), - }, - comment_span_start, - span.hi(), - false, - ); - - arg_items.extend(more_items); - } - - let fits_in_one_line = !generics_str_contains_newline - && (arg_items.is_empty() - || arg_items.len() == 1 && arg_item_strs[0].len() <= one_line_budget); - - for (item, arg) in arg_items.iter_mut().zip(arg_item_strs) { - item.item = Some(arg); + if params.is_empty() { + let comment = context + .snippet(mk_sp( + span.lo(), + // to remove ')' + span.hi() - BytePos(1), + )) + .trim(); + return Some(comment.to_owned()); } - - let last_line_ends_with_comment = arg_items - .iter() - .last() - .and_then(|item| item.post_comment.as_ref()) - .map_or(false, |s| s.trim().starts_with("//")); - - let (indent, trailing_comma) = match context.config.indent_style() { - IndentStyle::Block if fits_in_one_line => { - (indent.block_indent(context.config), SeparatorTactic::Never) - } - IndentStyle::Block => ( - indent.block_indent(context.config), - context.config.trailing_comma(), - ), - IndentStyle::Visual if last_line_ends_with_comment => { - (arg_indent, context.config.trailing_comma()) - } - IndentStyle::Visual => (arg_indent, SeparatorTactic::Never), - }; + let param_items: Vec<_> = itemize_list( + context.snippet_provider, + params.iter(), + ")", + ",", + |param| span_lo_for_param(param), + |param| param.ty.span.hi(), + |param| { + param + .rewrite(context, Shape::legacy(multi_line_budget, param_indent)) + .or_else(|| Some(context.snippet(param.span()).to_owned())) + }, + span.lo(), + span.hi(), + false, + ) + .collect(); let tactic = definitive_tactic( - &arg_items, - context.config.fn_args_density().to_list_tactic(), + ¶m_items, + context + .config + .fn_args_layout() + .to_list_tactic(param_items.len()), Separator::Comma, one_line_budget, ); @@ -2402,59 +2496,50 @@ enum ArgumentKind<'a> { DefinitiveListTactic::Horizontal => one_line_budget, _ => multi_line_budget, }; - - debug!("rewrite_args: budget: {}, tactic: {:?}", budget, tactic); - + let indent = match context.config.indent_style() { + IndentStyle::Block => indent.block_indent(context.config), + IndentStyle::Visual => param_indent, + }; let trailing_separator = if variadic { SeparatorTactic::Never } else { - trailing_comma + match context.config.indent_style() { + IndentStyle::Block => context.config.trailing_comma(), + IndentStyle::Visual => SeparatorTactic::Never, + } }; let fmt = ListFormatting::new(Shape::legacy(budget, indent), context.config) .tactic(tactic) .trailing_separator(trailing_separator) .ends_with_newline(tactic.ends_with_newline(context.config.indent_style())) .preserve_newline(true); - write_list(&arg_items, &fmt) + write_list(¶m_items, &fmt) } -fn arg_has_pattern(arg: &ast::Arg) -> bool { - if let ast::PatKind::Ident(_, ident, _) = arg.pat.node { - ident != symbol::keywords::Invalid.ident() - } else { - true - } -} - -fn compute_budgets_for_args( +fn compute_budgets_for_params( context: &RewriteContext<'_>, result: &str, indent: Indent, ret_str_len: usize, - newline_brace: bool, - has_braces: bool, + fn_brace_style: FnBraceStyle, force_vertical_layout: bool, ) -> Option<((usize, usize, Indent))> { debug!( - "compute_budgets_for_args {} {:?}, {}, {}", + "compute_budgets_for_params {} {:?}, {}, {:?}", result.len(), indent, ret_str_len, - newline_brace + fn_brace_style, ); // Try keeping everything on the same line. if !result.contains('\n') && !force_vertical_layout { // 2 = `()`, 3 = `() `, space is before ret_string. let overhead = if ret_str_len == 0 { 2 } else { 3 }; let mut used_space = indent.width() + result.len() + ret_str_len + overhead; - if has_braces { - if !newline_brace { - // 2 = `{}` - used_space += 2; - } - } else { - // 1 = `;` - used_space += 1; + match fn_brace_style { + FnBraceStyle::None => used_space += 1, // 1 = `;` + FnBraceStyle::SameLine => used_space += 2, // 2 = `{}` + FnBraceStyle::NextLine => (), } let one_line_budget = context.budget(used_space); @@ -2467,7 +2552,10 @@ fn compute_budgets_for_args( } IndentStyle::Visual => { let indent = indent + result.len() + 1; - let multi_line_overhead = indent.width() + if newline_brace { 2 } else { 4 }; + let multi_line_overhead = match fn_brace_style { + FnBraceStyle::SameLine => 4, + _ => 2, + } + indent.width(); (indent, context.budget(multi_line_overhead)) } }; @@ -2476,7 +2564,7 @@ fn compute_budgets_for_args( } } - // Didn't work. we must force vertical layout and put args on a newline. + // Didn't work. we must force vertical layout and put params on a newline. let new_indent = indent.block_indent(context.config); let used_space = match context.config.indent_style() { // 1 = `,` @@ -2487,16 +2575,21 @@ fn compute_budgets_for_args( Some((0, context.budget(used_space), new_indent)) } -fn newline_for_brace(config: &Config, where_clause: &ast::WhereClause) -> bool { +fn newline_for_brace(config: &Config, where_clause: &ast::WhereClause) -> FnBraceStyle { let predicate_count = where_clause.predicates.len(); if config.where_single_line() && predicate_count == 1 { - return false; + return FnBraceStyle::SameLine; } let brace_style = config.brace_style(); - brace_style == BraceStyle::AlwaysNextLine - || (brace_style == BraceStyle::SameLineWhere && predicate_count > 0) + let use_next_line = brace_style == BraceStyle::AlwaysNextLine + || (brace_style == BraceStyle::SameLineWhere && predicate_count > 0); + if use_next_line { + FnBraceStyle::NextLine + } else { + FnBraceStyle::SameLine + } } fn rewrite_generics( @@ -2505,8 +2598,8 @@ fn rewrite_generics( generics: &ast::Generics, shape: Shape, ) -> Option { - // FIXME: convert bounds to where clauses where they get too big or if - // there is a where clause at all. + // FIXME: convert bounds to where-clauses where they get too big or if + // there is a where-clause at all. if generics.params.is_empty() { return Some(ident.to_owned()); @@ -2516,7 +2609,11 @@ fn rewrite_generics( overflow::rewrite_with_angle_brackets(context, ident, params, shape, generics.span) } -pub fn generics_shape_from_config(config: &Config, shape: Shape, offset: usize) -> Option { +pub(crate) fn generics_shape_from_config( + config: &Config, + shape: Shape, + offset: usize, +) -> Option { match config.indent_style() { IndentStyle::Visual => shape.visual_indent(1 + offset).sub_width(offset + 2), IndentStyle::Block => { @@ -2538,25 +2635,104 @@ fn rewrite_where_clause_rfc_style( span_end: Option, span_end_before_where: BytePos, where_clause_option: WhereClauseOption, - is_args_multi_line: bool, ) -> Option { + let (where_keyword, allow_single_line) = rewrite_where_keyword( + context, + where_clause, + shape, + span_end_before_where, + where_clause_option, + )?; + + // 1 = `,` + let clause_shape = shape + .block() + .with_max_width(context.config) + .block_left(context.config.tab_spaces())? + .sub_width(1)?; + let force_single_line = context.config.where_single_line() + && where_clause.predicates.len() == 1 + && !where_clause_option.veto_single_line; + + let preds_str = rewrite_bounds_on_where_clause( + context, + where_clause, + clause_shape, + terminator, + span_end, + where_clause_option, + force_single_line, + )?; + + // 6 = `where ` + let clause_sep = + if allow_single_line && !preds_str.contains('\n') && 6 + preds_str.len() <= shape.width + || force_single_line + { + Cow::from(" ") + } else { + clause_shape.indent.to_string_with_newline(context.config) + }; + + Some(format!("{}{}{}", where_keyword, clause_sep, preds_str)) +} + +/// Rewrite `where` and comment around it. +fn rewrite_where_keyword( + context: &RewriteContext<'_>, + where_clause: &ast::WhereClause, + shape: Shape, + span_end_before_where: BytePos, + where_clause_option: WhereClauseOption, +) -> Option<(String, bool)> { let block_shape = shape.block().with_max_width(context.config); + // 1 = `,` + let clause_shape = block_shape + .block_left(context.config.tab_spaces())? + .sub_width(1)?; + + let comment_separator = |comment: &str, shape: Shape| { + if comment.is_empty() { + Cow::from("") + } else { + shape.indent.to_string_with_newline(context.config) + } + }; let (span_before, span_after) = missing_span_before_after_where(span_end_before_where, where_clause); let (comment_before, comment_after) = rewrite_comments_before_after_where(context, span_before, span_after, shape)?; - let starting_newline = if where_clause_option.snuggle && comment_before.is_empty() { - Cow::from(" ") - } else { - block_shape.indent.to_string_with_newline(context.config) + let starting_newline = match where_clause_option.snuggle { + WhereClauseSpace::Space if comment_before.is_empty() => Cow::from(" "), + WhereClauseSpace::None => Cow::from(""), + _ => block_shape.indent.to_string_with_newline(context.config), }; - let clause_shape = block_shape.block_left(context.config.tab_spaces())?; - // 1 = `,` - let clause_shape = clause_shape.sub_width(1)?; - // each clause on one line, trailing comma (except if suppress_comma) + let newline_before_where = comment_separator(&comment_before, shape); + let newline_after_where = comment_separator(&comment_after, clause_shape); + let result = format!( + "{}{}{}where{}{}", + starting_newline, comment_before, newline_before_where, newline_after_where, comment_after + ); + let allow_single_line = where_clause_option.allow_single_line + && comment_before.is_empty() + && comment_after.is_empty(); + + Some((result, allow_single_line)) +} + +/// Rewrite bounds on a where clause. +fn rewrite_bounds_on_where_clause( + context: &RewriteContext<'_>, + where_clause: &ast::WhereClause, + shape: Shape, + terminator: &str, + span_end: Option, + where_clause_option: WhereClauseOption, + force_single_line: bool, +) -> Option { let span_start = where_clause.predicates[0].span().lo(); // If we don't have the start of the next span, then use the end of the // predicates, but that means we miss comments. @@ -2570,64 +2746,30 @@ fn rewrite_where_clause_rfc_style( ",", |pred| pred.span().lo(), |pred| pred.span().hi(), - |pred| pred.rewrite(context, clause_shape), + |pred| pred.rewrite(context, shape), span_start, span_end, false, ); - let where_single_line = context.config.where_single_line() && len == 1 && !is_args_multi_line; - let comma_tactic = if where_clause_option.suppress_comma || where_single_line { + let comma_tactic = if where_clause_option.suppress_comma || force_single_line { SeparatorTactic::Never } else { context.config.trailing_comma() }; - // shape should be vertical only and only if we have `where_single_line` option enabled - // and the number of items of the where clause is equal to 1 - let shape_tactic = if where_single_line { + // shape should be vertical only and only if we have `force_single_line` option enabled + // and the number of items of the where-clause is equal to 1 + let shape_tactic = if force_single_line { DefinitiveListTactic::Horizontal } else { DefinitiveListTactic::Vertical }; - let fmt = ListFormatting::new(clause_shape, context.config) + let fmt = ListFormatting::new(shape, context.config) .tactic(shape_tactic) .trailing_separator(comma_tactic) .preserve_newline(true); - let preds_str = write_list(&items.collect::>(), &fmt)?; - - let comment_separator = |comment: &str, shape: Shape| { - if comment.is_empty() { - Cow::from("") - } else { - shape.indent.to_string_with_newline(context.config) - } - }; - let newline_before_where = comment_separator(&comment_before, shape); - let newline_after_where = comment_separator(&comment_after, clause_shape); - - // 6 = `where ` - let clause_sep = if where_clause_option.compress_where - && comment_before.is_empty() - && comment_after.is_empty() - && !preds_str.contains('\n') - && 6 + preds_str.len() <= shape.width - || where_single_line - { - Cow::from(" ") - } else { - clause_shape.indent.to_string_with_newline(context.config) - }; - Some(format!( - "{}{}{}where{}{}{}{}", - starting_newline, - comment_before, - newline_before_where, - newline_after_where, - comment_after, - clause_sep, - preds_str - )) + write_list(&items.collect::>(), &fmt) } fn rewrite_where_clause( @@ -2635,12 +2777,11 @@ fn rewrite_where_clause( where_clause: &ast::WhereClause, brace_style: BraceStyle, shape: Shape, - density: Density, + on_new_line: bool, terminator: &str, span_end: Option, span_end_before_where: BytePos, where_clause_option: WhereClauseOption, - is_args_multi_line: bool, ) -> Option { if where_clause.predicates.is_empty() { return Some(String::new()); @@ -2655,7 +2796,6 @@ fn rewrite_where_clause( span_end, span_end_before_where, where_clause_option, - is_args_multi_line, ); } @@ -2693,7 +2833,7 @@ fn rewrite_where_clause( let tactic = definitive_tactic(&item_vec, ListTactic::Vertical, Separator::Comma, budget); let mut comma_tactic = context.config.trailing_comma(); - // Kind of a hack because we don't usually have trailing commas in where clauses. + // Kind of a hack because we don't usually have trailing commas in where-clauses. if comma_tactic == SeparatorTactic::Vertical || where_clause_option.suppress_comma { comma_tactic = SeparatorTactic::Never; } @@ -2717,7 +2857,7 @@ fn rewrite_where_clause( } else { terminator.len() }; - if density == Density::Tall + if on_new_line || preds_str.contains('\n') || shape.indent.width() + " where ".len() + preds_str.len() + end_length > shape.width { @@ -2790,41 +2930,66 @@ fn format_generics( let shape = Shape::legacy(context.budget(used_width + offset.width()), offset); let mut result = rewrite_generics(context, "", generics, shape)?; - let same_line_brace = if !generics.where_clause.predicates.is_empty() || result.contains('\n') { + // If the generics are not parameterized then generics.span.hi() == 0, + // so we use span.lo(), which is the position after `struct Foo`. + let span_end_before_where = if !generics.params.is_empty() { + generics.span.hi() + } else { + span.lo() + }; + let (same_line_brace, missed_comments) = if !generics.where_clause.predicates.is_empty() { let budget = context.budget(last_line_used_width(&result, offset.width())); let mut option = WhereClauseOption::snuggled(&result); if brace_pos == BracePos::None { option.suppress_comma = true; } - // If the generics are not parameterized then generics.span.hi() == 0, - // so we use span.lo(), which is the position after `struct Foo`. - let span_end_before_where = if !generics.params.is_empty() { - generics.span.hi() - } else { - span.lo() - }; let where_clause_str = rewrite_where_clause( context, &generics.where_clause, brace_style, Shape::legacy(budget, offset.block_only()), - Density::Tall, + true, "{", Some(span.hi()), span_end_before_where, option, - false, )?; result.push_str(&where_clause_str); - brace_pos == BracePos::ForceSameLine - || brace_style == BraceStyle::PreferSameLine - || (generics.where_clause.predicates.is_empty() - && trimmed_last_line_width(&result) == 1) + ( + brace_pos == BracePos::ForceSameLine || brace_style == BraceStyle::PreferSameLine, + // missed comments are taken care of in #rewrite_where_clause + None, + ) } else { - brace_pos == BracePos::ForceSameLine - || trimmed_last_line_width(&result) == 1 - || brace_style != BraceStyle::AlwaysNextLine + ( + brace_pos == BracePos::ForceSameLine + || (result.contains('\n') && brace_style == BraceStyle::PreferSameLine + || brace_style != BraceStyle::AlwaysNextLine) + || trimmed_last_line_width(&result) == 1, + rewrite_missing_comment( + mk_sp( + span_end_before_where, + if brace_pos == BracePos::None { + span.hi() + } else { + context.snippet_provider.span_before(span, "{") + }, + ), + shape, + context, + ), + ) }; + // add missing comments + let missed_line_comments = missed_comments + .filter(|missed_comments| !missed_comments.is_empty()) + .map_or(false, |missed_comments| { + let is_block = is_last_comment_block(&missed_comments); + let sep = if is_block { " " } else { "\n" }; + result.push_str(sep); + result.push_str(&missed_comments); + !is_block + }); if brace_pos == BracePos::None { return Some(result); } @@ -2840,7 +3005,7 @@ fn format_generics( // 2 = ` {` 2 }; - let forbid_same_line_brace = overhead > remaining_budget; + let forbid_same_line_brace = missed_line_comments || overhead > remaining_budget; if !forbid_same_line_brace && same_line_brace { result.push(' '); } else { @@ -2859,22 +3024,21 @@ fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option // FIXME: this may be a faulty span from libsyntax. let span = mk_sp(self.span.lo(), self.span.hi() - BytePos(1)); - let item_str = match self.node { + let item_str = match self.kind { ast::ForeignItemKind::Fn(ref fn_decl, ref generics) => rewrite_fn_base( context, shape.indent, self.ident, &FnSig::new(fn_decl, generics, self.vis.clone()), span, - false, - false, + FnBraceStyle::None, ) .map(|(s, _)| format!("{};", s)), - ast::ForeignItemKind::Static(ref ty, is_mutable) => { + ast::ForeignItemKind::Static(ref ty, mutability) => { // FIXME(#21): we're dropping potential comments in between the - // function keywords here. + // function kw here. let vis = format_visibility(context, &self.vis); - let mut_str = if is_mutable { "mut " } else { "" }; + let mut_str = format_mutability(mutability); let prefix = format!( "{}static {}{}:", vis, @@ -2913,45 +3077,90 @@ fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option } } +/// Rewrite the attributes of an item. +fn rewrite_attrs( + context: &RewriteContext<'_>, + item: &ast::Item, + item_str: &str, + shape: Shape, +) -> Option { + let attrs = filter_inline_attrs(&item.attrs, item.span()); + let attrs_str = attrs.rewrite(context, shape)?; + + let missed_span = if attrs.is_empty() { + mk_sp(item.span.lo(), item.span.lo()) + } else { + mk_sp(attrs[attrs.len() - 1].span.hi(), item.span.lo()) + }; + + let allow_extend = if attrs.len() == 1 { + let line_len = attrs_str.len() + 1 + item_str.len(); + !attrs.first().unwrap().is_sugared_doc + && context.config.inline_attribute_width() >= line_len + } else { + false + }; + + combine_strs_with_missing_comments( + context, + &attrs_str, + &item_str, + missed_span, + shape, + allow_extend, + ) +} + /// Rewrite an inline mod. -pub fn rewrite_mod(context: &RewriteContext<'_>, item: &ast::Item) -> String { +/// The given shape is used to format the mod's attributes. +pub(crate) fn rewrite_mod( + context: &RewriteContext<'_>, + item: &ast::Item, + attrs_shape: Shape, +) -> Option { let mut result = String::with_capacity(32); result.push_str(&*format_visibility(context, &item.vis)); result.push_str("mod "); result.push_str(rewrite_ident(context, item.ident)); result.push(';'); - result + rewrite_attrs(context, item, &result, attrs_shape) } -/// Rewrite `extern crate foo;` WITHOUT attributes. -pub fn rewrite_extern_crate(context: &RewriteContext<'_>, item: &ast::Item) -> Option { +/// Rewrite `extern crate foo;`. +/// The given shape is used to format the extern crate's attributes. +pub(crate) fn rewrite_extern_crate( + context: &RewriteContext<'_>, + item: &ast::Item, + attrs_shape: Shape, +) -> Option { assert!(is_extern_crate(item)); let new_str = context.snippet(item.span); - Some(if contains_comment(new_str) { + let item_str = if contains_comment(new_str) { new_str.to_owned() } else { let no_whitespace = &new_str.split_whitespace().collect::>().join(" "); String::from(&*Regex::new(r"\s;").unwrap().replace(no_whitespace, ";")) - }) + }; + rewrite_attrs(context, item, &item_str, attrs_shape) } -/// Returns true for `mod foo;`, false for `mod foo { .. }`. -pub fn is_mod_decl(item: &ast::Item) -> bool { - match item.node { +/// Returns `true` for `mod foo;`, false for `mod foo { .. }`. +pub(crate) fn is_mod_decl(item: &ast::Item) -> bool { + match item.kind { ast::ItemKind::Mod(ref m) => m.inner.hi() != item.span.hi(), _ => false, } } -pub fn is_use_item(item: &ast::Item) -> bool { - match item.node { +pub(crate) fn is_use_item(item: &ast::Item) -> bool { + match item.kind { ast::ItemKind::Use(_) => true, _ => false, } } -pub fn is_extern_crate(item: &ast::Item) -> bool { - match item.node { +pub(crate) fn is_extern_crate(item: &ast::Item) -> bool { + match item.kind { ast::ItemKind::ExternCrate(..) => true, _ => false, }