use syntax::codemap::{BytePos, Span};
use {Indent, Shape, Spanned};
-use codemap::SpanUtils;
-use comment::{contains_comment, recover_comment_removed, rewrite_comment, FindUncommented};
+use codemap::{LineRangeUtils, SpanUtils};
+use comment::{combine_strs_with_missing_comments, contains_comment, recover_comment_removed,
+ recover_missing_comment_in_span, rewrite_missing_comment, FindUncommented};
use config::{BraceStyle, Config, Density, IndentStyle, ReturnIndent, Style};
use expr::{format_expr, is_empty_block, is_simple_block_stmt, rewrite_assign_rhs,
rewrite_call_inner, ExprType};
use lists::{definitive_tactic, itemize_list, write_list, DefinitiveListTactic, ListFormatting,
- ListItem, ListTactic, SeparatorTactic};
+ ListItem, ListTactic, Separator, SeparatorPlace, SeparatorTactic};
use rewrite::{Rewrite, RewriteContext};
use types::join_bounds;
-use utils::{colon_spaces, contains_skip, end_typaram, format_defaultness, format_mutability,
- format_unsafety, format_visibility, last_line_width, mk_sp, semicolon_for_expr,
- stmt_expr, trim_newlines, trimmed_last_line_width, wrap_str};
+use utils::{colon_spaces, contains_skip, end_typaram, first_line_width, format_abi,
+ format_constness, format_defaultness, format_mutability, format_unsafety,
+ format_visibility, is_attributes_extendable, last_line_contains_single_line_comment,
+ last_line_used_width, last_line_width, mk_sp, semicolon_for_expr, stmt_expr,
+ trim_newlines, trimmed_last_line_width, wrap_str};
use vertical::rewrite_with_alignment;
use visitor::FmtVisitor;
)
}
-
// Statements of the form
// let pat: ty = init;
impl Rewrite for ast::Local {
shape.width,
shape.indent
);
- let mut result = "let ".to_owned();
+
+ skip_out_of_file_lines_range!(context, self.span);
+
+ if contains_skip(&self.attrs) {
+ return None;
+ }
+
+ let attrs_str = try_opt!(self.attrs.rewrite(context, shape));
+ let mut result = if attrs_str.is_empty() {
+ "let ".to_owned()
+ } else {
+ try_opt!(combine_strs_with_missing_comments(
+ context,
+ &attrs_str,
+ "let ",
+ mk_sp(
+ self.attrs.last().map(|a| a.span.hi()).unwrap(),
+ self.span.lo(),
+ ),
+ shape,
+ false,
+ ))
+ };
// 4 = "let ".len()
let pat_shape = try_opt!(shape.offset_left(4));
// 1 = ;
let pat_shape = try_opt!(pat_shape.sub_width(1));
- let pat_str = try_opt!(self.pat.rewrite(&context, pat_shape));
+ let pat_str = try_opt!(self.pat.rewrite(context, pat_shape));
result.push_str(&pat_str);
// String that is placed within the assignment pattern and expression.
let infix = {
- let mut infix = String::new();
+ let mut infix = String::with_capacity(32);
if let Some(ref ty) = self.ty {
let separator = type_annotation_separator(context.config);
// 1 = trailing semicolon;
let nested_shape = try_opt!(shape.sub_width(1));
- result = try_opt!(rewrite_assign_rhs(&context, result, ex, nested_shape));
+ result = try_opt!(rewrite_assign_rhs(context, result, ex, nested_shape));
}
result.push(';');
if !item.body.is_empty() || contains_comment(&snippet[brace_pos..]) {
// FIXME: this skips comments between the extern keyword and the opening
// brace.
- self.last_pos = item.span.lo + BytePos(brace_pos as u32 + 1);
+ self.last_pos = item.span.lo() + BytePos(brace_pos as u32 + 1);
self.block_indent = self.block_indent.block_indent(self.config);
if item.body.is_empty() {
- self.format_missing_no_indent(item.span.hi - BytePos(1));
+ self.format_missing_no_indent(item.span.hi() - BytePos(1));
self.block_indent = self.block_indent.block_unindent(self.config);
self.buffer
}
self.block_indent = self.block_indent.block_unindent(self.config);
- self.format_missing_with_indent(item.span.hi - BytePos(1));
+ self.format_missing_with_indent(item.span.hi() - BytePos(1));
}
}
self.buffer.push_str("}");
- self.last_pos = item.span.hi;
+ self.last_pos = item.span.hi();
}
fn format_body_element(&mut self, element: &BodyElement) {
match *element {
- BodyElement::ForeignItem(ref item) => self.format_foreign_item(item),
+ BodyElement::ForeignItem(item) => self.format_foreign_item(item),
}
}
self.format_item(item);
}
- fn format_foreign_item(&mut self, item: &ast::ForeignItem) {
- self.format_missing_with_indent(item.span.lo);
- // Drop semicolon or it will be interpreted as comment.
- // FIXME: this may be a faulty span from libsyntax.
- let span = mk_sp(item.span.lo, item.span.hi - BytePos(1));
- match item.node {
- ast::ForeignItemKind::Fn(ref fn_decl, ref generics) => {
- let indent = self.block_indent;
- let rewrite = rewrite_fn_base(
- &self.get_context(),
- indent,
- item.ident,
- fn_decl,
- generics,
- ast::Unsafety::Normal,
- ast::Constness::NotConst,
- ast::Defaultness::Final,
- // These are not actually rust functions,
- // but we format them as such.
- abi::Abi::Rust,
- &item.vis,
- span,
- false,
- false,
- false,
- );
-
- match rewrite {
- Some((new_fn, _)) => {
- self.buffer.push_str(&new_fn);
- self.buffer.push_str(";");
- }
- None => self.format_missing(item.span.hi),
- }
- }
- ast::ForeignItemKind::Static(ref ty, is_mutable) => {
- // FIXME(#21): we're dropping potential comments in between the
- // function keywords here.
- let vis = format_visibility(&item.vis);
- let mut_str = if is_mutable { "mut " } else { "" };
- let prefix = format!("{}static {}{}: ", vis, mut_str, item.ident);
- let offset = self.block_indent + prefix.len();
- // 1 = ;
- let shape = Shape::indented(offset, self.config).sub_width(1).unwrap();
- let rewrite = ty.rewrite(&self.get_context(), shape);
-
- match rewrite {
- Some(result) => {
- self.buffer.push_str(&prefix);
- self.buffer.push_str(&result);
- self.buffer.push_str(";");
- }
- None => self.format_missing(item.span.hi),
- }
- }
- }
-
- self.last_pos = item.span.hi;
+ fn format_foreign_item(&mut self, item: &ast::ForeignItem) {
+ let rewrite = item.rewrite(&self.get_context(), self.shape());
+ self.push_rewrite(item.span(), rewrite);
+ self.last_pos = item.span.hi();
}
pub fn rewrite_fn(
span: Span,
block: &ast::Block,
) -> Option<String> {
- let mut newline_brace = newline_for_brace(self.config, &generics.where_clause);
let context = self.get_context();
- let block_snippet = self.snippet(mk_sp(block.span.lo, block.span.hi));
- let has_body = !block_snippet[1..block_snippet.len() - 1].trim().is_empty() ||
- !context.config.fn_empty_single_line();
+ let block_snippet = self.snippet(mk_sp(block.span.lo(), block.span.hi()));
+ let has_body = !block_snippet[1..block_snippet.len() - 1].trim().is_empty()
+ || !context.config.fn_empty_single_line();
+ let mut newline_brace = newline_for_brace(self.config, &generics.where_clause, has_body);
let (mut result, force_newline_brace) = try_opt!(rewrite_fn_base(
&context,
if force_newline_brace {
newline_brace = true;
- } else if self.config.fn_brace_style() != BraceStyle::AlwaysNextLine &&
- !result.contains('\n')
+ } else if self.config.fn_brace_style() != BraceStyle::AlwaysNextLine
+ && !result.contains('\n')
{
newline_brace = false;
}
span: Span,
) -> Option<String> {
// Drop semicolon or it will be interpreted as comment.
- let span = mk_sp(span.lo, span.hi - BytePos(1));
+ let span = mk_sp(span.lo(), span.hi() - BytePos(1));
let context = self.get_context();
let (mut result, _) = try_opt!(rewrite_fn_base(
let codemap = self.get_context().codemap;
- if self.config.fn_empty_single_line() && is_empty_block(block, codemap) &&
- self.block_indent.width() + fn_str.len() + 2 <= self.config.max_width()
+ if self.config.fn_empty_single_line() && is_empty_block(block, codemap)
+ && self.block_indent.width() + fn_str.len() + 2 <= self.config.max_width()
{
return Some(format!("{}{{}}", fn_str));
}
if self.config.fn_single_line() && is_simple_block_stmt(block, codemap) {
let rewrite = {
- if let Some(ref stmt) = block.stmts.first() {
+ if let Some(stmt) = block.stmts.first() {
match stmt_expr(stmt) {
Some(e) => {
let suffix = if semicolon_for_expr(&self.get_context(), e) {
""
};
- format_expr(
- &e,
- ExprType::Statement,
- &self.get_context(),
- Shape::indented(self.block_indent, self.config),
- ).map(|s| s + suffix)
+ format_expr(e, ExprType::Statement, &self.get_context(), self.shape())
+ .map(|s| s + suffix)
.or_else(|| Some(self.snippet(e.span)))
}
- None => stmt.rewrite(
- &self.get_context(),
- Shape::indented(self.block_indent, self.config),
- ),
+ None => stmt.rewrite(&self.get_context(), self.shape()),
}
} else {
None
let enum_snippet = self.snippet(span);
let brace_pos = enum_snippet.find_uncommented("{").unwrap();
- let body_start = span.lo + BytePos(brace_pos as u32 + 1);
+ let body_start = span.lo() + BytePos(brace_pos as u32 + 1);
let generics_str = format_generics(
&self.get_context(),
generics,
self.config.item_brace_style(),
enum_def.variants.is_empty(),
self.block_indent,
- mk_sp(span.lo, body_start),
+ mk_sp(span.lo(), body_start),
last_line_width(&enum_header),
).unwrap();
self.buffer.push_str(&generics_str);
self.last_pos = body_start;
self.block_indent = self.block_indent.block_indent(self.config);
- let variant_list = self.format_variant_list(enum_def, body_start, span.hi - BytePos(1));
+ let variant_list = self.format_variant_list(enum_def, body_start, span.hi() - BytePos(1));
match variant_list {
Some(ref body_str) => self.buffer.push_str(body_str),
None => if contains_comment(&enum_snippet[brace_pos..]) {
- self.format_missing_no_indent(span.hi - BytePos(1))
- } else {
- self.format_missing(span.hi - BytePos(1))
+ self.format_missing_no_indent(span.hi() - BytePos(1))
},
}
self.block_indent = self.block_indent.block_unindent(self.config);
.push_str(&self.block_indent.to_string(self.config));
}
self.buffer.push_str("}");
- self.last_pos = span.hi;
+ self.last_pos = span.hi();
}
// Format the body of an enum definition
enum_def.variants.iter(),
"}",
|f| if !f.node.attrs.is_empty() {
- f.node.attrs[0].span.lo
+ f.node.attrs[0].span.lo()
} else {
- f.span.lo
+ f.span.lo()
},
- |f| f.span.hi,
+ |f| f.span.hi(),
|f| self.format_variant(f),
body_lo,
body_hi,
+ false,
);
- let shape = Shape::indented(self.block_indent, self.config)
- .sub_width(2)
- .unwrap();
+ let shape = self.shape().sub_width(2).unwrap();
let fmt = ListFormatting {
tactic: DefinitiveListTactic::Vertical,
separator: ",",
trailing_separator: self.config.trailing_comma(),
+ separator_place: SeparatorPlace::Back,
shape: shape,
ends_with_newline: true,
preserve_newline: true,
// Variant of an enum.
fn format_variant(&self, field: &ast::Variant) -> Option<String> {
if contains_skip(&field.node.attrs) {
- let lo = field.node.attrs[0].span.lo;
- let span = mk_sp(lo, field.span.hi);
+ let lo = field.node.attrs[0].span.lo();
+ let span = mk_sp(lo, field.span.hi());
return Some(self.snippet(span));
}
let context = self.get_context();
let indent = self.block_indent;
- let mut result = try_opt!(
- field
- .node
- .attrs
- .rewrite(&context, Shape::indented(indent, self.config))
- );
- if !result.is_empty() {
- let shape = Shape {
- width: context.config.max_width(),
- indent: self.block_indent,
- offset: self.block_indent.alignment,
- };
- let missing_comment = rewrite_missing_comment_on_field(
- &context,
- shape,
- field.node.attrs[field.node.attrs.len() - 1].span.hi,
- field.span.lo,
- &mut result,
- ).unwrap_or(String::new());
- result.push_str(&missing_comment);
- }
+ let shape = self.shape();
+ let attrs_str = try_opt!(field.node.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 {
ast::VariantData::Tuple(..) | ast::VariantData::Struct(..) => {
// FIXME: Should limit the width, as we have a trailing comma
- format_struct(
+ try_opt!(format_struct(
&context,
"",
field.node.name,
field.span,
indent,
Some(self.config.struct_variant_width()),
- )
+ ))
}
- ast::VariantData::Unit(..) => {
- let tag = if let Some(ref expr) = field.node.disr_expr {
+ ast::VariantData::Unit(..) => if let Some(ref expr) = field.node.disr_expr {
+ let one_line_width =
+ field.node.name.to_string().len() + self.snippet(expr.span).len() + 3;
+ if one_line_width <= shape.width {
format!("{} = {}", field.node.name, self.snippet(expr.span))
} else {
- field.node.name.to_string()
- };
-
- wrap_str(
- tag,
- self.config.max_width(),
- Shape::indented(indent, self.config),
- )
- }
+ format!(
+ "{}\n{}{}",
+ field.node.name,
+ shape
+ .indent
+ .block_indent(self.config)
+ .to_string(self.config),
+ self.snippet(expr.span)
+ )
+ }
+ } else {
+ String::from(field.node.name.to_string())
+ },
};
- if let Some(variant_str) = variant_body {
- result.push_str(&variant_str);
- Some(result)
- } else {
- None
- }
+ let attrs_extendable = attrs_str.is_empty()
+ || (context.config.attributes_on_same_line_as_variant()
+ && is_attributes_extendable(&attrs_str));
+ combine_strs_with_missing_comments(
+ &context,
+ &attrs_str,
+ &variant_body,
+ span,
+ shape,
+ attrs_extendable,
+ )
}
}
where_span_end: Option<BytePos>,
) -> Option<String> {
if let ast::ItemKind::Impl(_, _, _, ref generics, _, ref self_ty, ref items) = item.node {
- let mut result = String::new();
+ let mut result = String::with_capacity(128);
let ref_and_type = try_opt!(format_impl_ref_and_type(context, item, offset));
+ let indent_str = offset.to_string(context.config);
+ let sep = format!("\n{}", &indent_str);
result.push_str(&ref_and_type);
let where_budget = if result.contains('\n') {
context.config.max_width()
} else {
- context
- .config
- .max_width()
- .checked_sub(last_line_width(&result))
- .unwrap_or(0)
+ context.budget(last_line_width(&result))
};
+ let option = WhereClauseOption::snuggled(&ref_and_type);
let where_clause_str = try_opt!(rewrite_where_clause(
context,
&generics.where_clause,
Shape::legacy(where_budget, offset.block_only()),
context.config.where_density(),
"{",
- false,
- last_line_width(&ref_and_type) == 1,
where_span_end,
- item.span,
- self_ty.span.hi,
+ self_ty.span.hi(),
+ option,
));
+ // 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 {
+ match recover_missing_comment_in_span(
+ mk_sp(self_ty.span.hi(), hi),
+ Shape::indented(offset, context.config),
+ context,
+ last_line_width(&result),
+ ) {
+ Some(ref missing_comment) if !missing_comment.is_empty() => {
+ result.push_str(missing_comment);
+ }
+ _ => (),
+ }
+ }
+ }
+
if try_opt!(is_impl_single_line(
context,
- &items,
+ items,
&result,
&where_clause_str,
- &item,
+ item,
)) {
result.push_str(&where_clause_str);
- if where_clause_str.contains('\n') {
- let white_space = offset.to_string(context.config);
- result.push_str(&format!("\n{}{{\n{}}}", &white_space, &white_space));
+ if where_clause_str.contains('\n') || last_line_contains_single_line_comment(&result) {
+ result.push_str(&format!("{}{{{}}}", &sep, &sep));
} else {
result.push_str(" {}");
}
result.push_str(&where_clause_str);
match context.config.item_brace_style() {
- BraceStyle::AlwaysNextLine => {
- result.push('\n');
- result.push_str(&offset.to_string(context.config));
- }
+ _ if last_line_contains_single_line_comment(&result) => result.push_str(&sep),
+ BraceStyle::AlwaysNextLine => result.push_str(&sep),
BraceStyle::PreferSameLine => result.push(' '),
BraceStyle::SameLineWhere => if !where_clause_str.is_empty() {
- result.push('\n');
- result.push_str(&offset.to_string(context.config));
+ result.push_str(&sep);
} else {
result.push(' ');
},
if !items.is_empty() || contains_comment(&snippet[open_pos..]) {
let mut visitor = FmtVisitor::from_codemap(context.parse_session, context.config);
visitor.block_indent = offset.block_only().block_indent(context.config);
- visitor.last_pos = item.span.lo + BytePos(open_pos as u32);
+ visitor.last_pos = item.span.lo() + BytePos(open_pos as u32);
visitor.visit_attrs(&item.attrs, ast::AttrStyle::Inner);
for item in items {
visitor.visit_impl_item(item);
}
- visitor.format_missing(item.span.hi - BytePos(1));
+ visitor.format_missing(item.span.hi() - BytePos(1));
let inner_indent_str = visitor.block_indent.to_string(context.config);
let outer_indent_str = offset.block_only().to_string(context.config);
}
if result.chars().last().unwrap() == '{' {
- result.push('\n');
- result.push_str(&offset.to_string(context.config));
+ result.push_str(&sep);
}
result.push('}');
let open_pos = try_opt!(snippet.find_uncommented("{")) + 1;
Some(
- context.config.impl_empty_single_line() && items.is_empty() &&
- result.len() + where_clause_str.len() <= context.config.max_width() &&
- !contains_comment(&snippet[open_pos..]),
+ context.config.impl_empty_single_line() && items.is_empty() && !result.contains('\n')
+ && result.len() + where_clause_str.len() <= context.config.max_width()
+ && !contains_comment(&snippet[open_pos..]),
)
}
_,
) = item.node
{
- let mut result = String::new();
+ let mut result = String::with_capacity(128);
result.push_str(&format_visibility(&item.vis));
- result.push_str(&format_defaultness(defaultness));
+ result.push_str(format_defaultness(defaultness));
result.push_str(format_unsafety(unsafety));
result.push_str("impl");
let lo = context.codemap.span_after(item.span, "impl");
let hi = match *trait_ref {
- Some(ref tr) => tr.path.span.lo,
- None => self_ty.span.lo,
+ Some(ref tr) => tr.path.span.lo(),
+ None => self_ty.span.lo(),
};
let shape = try_opt!(generics_shape_from_config(
context.config,
let result_len = result.len();
if let Some(trait_ref_str) = rewrite_trait_ref(
context,
- &trait_ref,
+ trait_ref,
offset,
&generics_str,
true,
));
result.push_str(&try_opt!(rewrite_trait_ref(
context,
- &trait_ref,
+ trait_ref,
offset,
&generics_str,
false,
};
let used_space = last_line_width(&result) + trait_ref_overhead + curly_brace_overhead;
// 1 = space before the type.
- let budget = context
- .config
- .max_width()
- .checked_sub(used_space + 1)
- .unwrap_or(0);
+ let budget = context.budget(used_space + 1);
if let Some(self_ty_str) = self_ty.rewrite(context, Shape::legacy(budget, offset)) {
if !self_ty_str.contains('\n') {
if trait_ref.is_some() {
if trait_ref.is_some() {
result.push_str("for ");
}
- let budget = context.config.max_width() - last_line_width(&result);
+ let budget = context.budget(last_line_width(&result));
let type_offset = match context.config.where_style() {
Style::Legacy => new_line_offset + trait_ref_overhead,
Style::Rfc => new_line_offset,
result_len: usize,
) -> Option<String> {
// 1 = space between generics and trait_ref
- let used_space = 1 + polarity_str.len() + if generics_str.contains('\n') {
- last_line_width(&generics_str)
- } else {
- result_len + generics_str.len()
- };
+ let used_space = 1 + polarity_str.len() + last_line_used_width(generics_str, result_len);
let shape = Shape::indented(offset + used_space, context.config);
if let Some(trait_ref_str) = trait_ref.rewrite(context, shape) {
if !(retry && trait_ref_str.contains('\n')) {
if let ast::ItemKind::Trait(unsafety, ref generics, ref type_param_bounds, ref trait_items) =
item.node
{
- let mut result = String::new();
+ let mut result = String::with_capacity(128);
let header = format!(
"{}{}trait {}",
format_visibility(&item.vis),
context,
generics,
shape,
- mk_sp(item.span.lo, body_lo),
+ mk_sp(item.span.lo(), body_lo),
));
result.push_str(&generics_str);
));
// If the trait, generics, and trait bound cannot fit on the same line,
// put the trait bounds on an indented new line
- if offset.width() + last_line_width(&result) + trait_bound_str.len() >
- context.config.comment_width()
+ if offset.width() + last_line_width(&result) + trait_bound_str.len()
+ > context.config.comment_width()
{
result.push('\n');
let trait_indent = offset.block_only().block_indent(context.config);
let has_body = !trait_items.is_empty();
- let where_density = if (context.config.where_density() == Density::Compressed &&
- (!result.contains('\n') || context.config.fn_args_layout() == IndentStyle::Block)) ||
- (context.config.fn_args_layout() == IndentStyle::Block && result.is_empty()) ||
- (context.config.where_density() == Density::CompressedIfEmpty && !has_body &&
- !result.contains('\n'))
+ let where_density = if (context.config.where_density() == Density::Compressed
+ && (!result.contains('\n') || context.config.fn_args_layout() == IndentStyle::Block))
+ || (context.config.fn_args_layout() == IndentStyle::Block && result.is_empty())
+ || (context.config.where_density() == Density::CompressedIfEmpty && !has_body
+ && !result.contains('\n'))
{
Density::Compressed
} else {
Density::Tall
};
- let where_budget = try_opt!(
- context
- .config
- .max_width()
- .checked_sub(last_line_width(&result))
- );
+ let where_budget = context.budget(last_line_width(&result));
let pos_before_where = if type_param_bounds.is_empty() {
- if generics.where_clause.predicates.is_empty() {
- // We do not use this, so it does not matter
- item.span.lo
- } else {
- let snippet = context.snippet(item.span);
- let where_pos = snippet.find_uncommented("where");
- item.span.lo + where_pos.map_or(BytePos(0), |p| BytePos(p as u32))
- }
+ generics.where_clause.span.lo()
} else {
- type_param_bounds[type_param_bounds.len() - 1].span().hi
+ type_param_bounds[type_param_bounds.len() - 1].span().hi()
};
+ let option = WhereClauseOption::snuggled(&generics_str);
let where_clause_str = try_opt!(rewrite_where_clause(
context,
&generics.where_clause,
Shape::legacy(where_budget, offset.block_only()),
where_density,
"{",
- false,
- trait_bound_str.is_empty() && last_line_width(&generics_str) == 1,
None,
- item.span,
pos_before_where,
+ option,
));
// 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()
+ if !where_clause_str.contains('\n')
+ && last_line_width(&result) + where_clause_str.len() + offset.width()
+ > context.config.comment_width()
{
result.push('\n');
let width = offset.block_indent + context.config.tab_spaces() - 1;
}
result.push_str(&where_clause_str);
+ if generics.where_clause.predicates.is_empty() {
+ let item_snippet = context.snippet(item.span);
+ if let Some(lo) = item_snippet.chars().position(|c| c == '/') {
+ // 1 = `{`
+ let comment_hi = body_lo - BytePos(1);
+ let comment_lo = item.span.lo() + BytePos(lo as u32);
+ if comment_lo < comment_hi {
+ match recover_missing_comment_in_span(
+ mk_sp(comment_lo, comment_hi),
+ Shape::indented(offset, context.config),
+ context,
+ last_line_width(&result),
+ ) {
+ Some(ref missing_comment) if !missing_comment.is_empty() => {
+ result.push_str(missing_comment);
+ }
+ _ => (),
+ }
+ }
+ }
+ }
+
match context.config.item_brace_style() {
+ _ if last_line_contains_single_line_comment(&result) => {
+ result.push('\n');
+ result.push_str(&offset.to_string(context.config));
+ }
BraceStyle::AlwaysNextLine => {
result.push('\n');
result.push_str(&offset.to_string(context.config));
}
BraceStyle::PreferSameLine => result.push(' '),
- BraceStyle::SameLineWhere => if !where_clause_str.is_empty() &&
- (!trait_items.is_empty() || result.contains('\n'))
+ BraceStyle::SameLineWhere => if !where_clause_str.is_empty()
+ && (!trait_items.is_empty() || result.contains('\n'))
{
result.push('\n');
result.push_str(&offset.to_string(context.config));
if !trait_items.is_empty() || contains_comment(&snippet[open_pos..]) {
let mut visitor = FmtVisitor::from_codemap(context.parse_session, context.config);
visitor.block_indent = offset.block_only().block_indent(context.config);
- visitor.last_pos = item.span.lo + BytePos(open_pos as u32);
+ visitor.last_pos = item.span.lo() + BytePos(open_pos as u32);
for item in trait_items {
visitor.visit_trait_item(item);
}
- visitor.format_missing(item.span.hi - BytePos(1));
+ visitor.format_missing(item.span.hi() - BytePos(1));
let inner_indent_str = visitor.block_indent.to_string(context.config);
let outer_indent_str = offset.block_only().to_string(context.config);
context.config.item_brace_style(),
fields.is_empty(),
offset,
- mk_sp(span.lo, body_lo),
+ mk_sp(span.lo(), body_lo),
last_line_width(&result),
)),
None => {
// 3 = ` {}`, 2 = ` {`.
let overhead = if fields.is_empty() { 3 } else { 2 };
- if (context.config.item_brace_style() == BraceStyle::AlwaysNextLine &&
- !fields.is_empty()) ||
- context
- .config
- .max_width()
- .checked_sub(result.len())
- .unwrap_or(0) < overhead
+ if (context.config.item_brace_style() == BraceStyle::AlwaysNextLine
+ && !fields.is_empty())
+ || context.config.max_width() < overhead + result.len()
{
format!("\n{}{{", offset.block_only().to_string(context.config))
} else {
};
// 1 = `}`
let overhead = if fields.is_empty() { 1 } else { 0 };
- let max_len = context
- .config
- .max_width()
- .checked_sub(offset.width())
- .unwrap_or(0);
- if !generics_str.contains('\n') && result.len() + generics_str.len() + overhead > max_len {
+ let total_width = result.len() + generics_str.len() + overhead;
+ if !generics_str.is_empty() && !generics_str.contains('\n')
+ && total_width > context.config.max_width()
+ {
result.push('\n');
result.push_str(&offset.to_string(context.config));
- result.push_str(&generics_str.trim_left());
+ result.push_str(generics_str.trim_left());
} else {
result.push_str(&generics_str);
}
if fields.is_empty() {
- let snippet = context.snippet(mk_sp(body_lo, span.hi - BytePos(1)));
+ let snippet = context.snippet(mk_sp(body_lo, span.hi() - BytePos(1)));
if snippet.trim().is_empty() {
// `struct S {}`
} else if snippet.trim_right_matches(&[' ', '\t'][..]).ends_with('\n') {
// fix indent
- result.push_str(&snippet.trim_right());
+ result.push_str(snippet.trim_right());
result.push('\n');
result.push_str(&offset.to_string(context.config));
} else {
}
// 3 = ` ` and ` }`
- let one_line_budget = context
- .config
- .max_width()
- .checked_sub(result.len() + 3 + offset.width())
- .unwrap_or(0);
+ let one_line_budget = context.budget(result.len() + 3 + offset.width());
let one_line_budget =
one_line_width.map_or(0, |one_line_width| min(one_line_width, one_line_budget));
fields,
context,
Shape::indented(offset, context.config),
- mk_sp(body_lo, span.hi),
+ mk_sp(body_lo, span.hi()),
one_line_budget,
));
let body_lo = if fields.is_empty() {
context.codemap.span_after(span, "(")
} else {
- fields[0].span.lo
+ fields[0].span.lo()
};
let body_hi = if fields.is_empty() {
context.codemap.span_after(span, ")")
} else {
// This is a dirty hack to work around a missing `)` from the span of the last field.
let last_arg_span = fields[fields.len() - 1].span;
- if context.snippet(last_arg_span).ends_with(")") {
- last_arg_span.hi
+ if context.snippet(last_arg_span).ends_with(')') {
+ last_arg_span.hi()
} else {
context
.codemap
- .span_after(mk_sp(last_arg_span.hi, span.hi), ")")
+ .span_after(mk_sp(last_arg_span.hi(), span.hi()), ")")
}
};
Some(generics) => {
let budget = context.budget(last_line_width(&header_str));
let shape = Shape::legacy(budget, offset);
- let g_span = mk_sp(span.lo, body_lo);
+ let g_span = mk_sp(span.lo(), body_lo);
let generics_str = try_opt!(rewrite_generics(context, generics, shape, g_span));
result.push_str(&generics_str);
let where_budget = context.budget(last_line_width(&result));
+ let option = WhereClauseOption::new(true, false);
try_opt!(rewrite_where_clause(
context,
&generics.where_clause,
Shape::legacy(where_budget, offset.block_only()),
Density::Compressed,
";",
- true,
- false,
None,
- span,
body_hi,
+ option,
))
}
None => "".to_owned(),
if fields.is_empty() {
// 3 = `();`
- let used_width = if result.contains('\n') {
- last_line_width(&result) + 3
- } else {
- offset.width() + result.len() + 3
- };
+ let used_width = last_line_used_width(&result, offset.width()) + 3;
if used_width > context.config.max_width() {
result.push('\n');
result.push_str(&offset
if snippet.is_empty() {
// `struct S ()`
} else if snippet.trim_right_matches(&[' ', '\t'][..]).ends_with('\n') {
- result.push_str(&snippet.trim_right());
+ result.push_str(snippet.trim_right());
result.push('\n');
result.push_str(&offset.to_string(context.config));
} else {
result.push_str(&body);
}
- if !where_clause_str.is_empty() && !where_clause_str.contains('\n') &&
- (result.contains('\n') ||
- offset.block_indent + result.len() + where_clause_str.len() + 1 >
- context.config.max_width())
+ if !where_clause_str.is_empty() && !where_clause_str.contains('\n')
+ && (result.contains('\n')
+ || 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.
vis: &ast::Visibility,
span: Span,
) -> Option<String> {
- let mut result = String::new();
+ let mut result = String::with_capacity(128);
result.push_str(&format_visibility(vis));
result.push_str("type ");
// 2 = `= `
let shape = try_opt!(Shape::indented(indent + result.len(), context.config).sub_width(2));
- let g_span = mk_sp(context.codemap.span_after(span, "type"), ty.span.lo);
+ let g_span = mk_sp(context.codemap.span_after(span, "type"), ty.span.lo());
let generics_str = try_opt!(rewrite_generics(context, generics, shape, g_span));
result.push_str(&generics_str);
- let where_budget = try_opt!(
- context
- .config
- .max_width()
- .checked_sub(last_line_width(&result))
- );
+ let where_budget = context.budget(last_line_width(&result));
+ let option = WhereClauseOption::snuggled(&result);
let where_clause_str = try_opt!(rewrite_where_clause(
context,
&generics.where_clause,
Shape::legacy(where_budget, indent),
context.config.where_density(),
"=",
- true,
- true,
- Some(span.hi),
- span,
- generics.span.hi,
+ Some(span.hi()),
+ generics.span.hi(),
+ option,
));
result.push_str(&where_clause_str);
- result.push_str(" = ");
+ if where_clause_str.is_empty() {
+ result.push_str(" = ");
+ } else {
+ result.push_str(&format!("\n{}= ", indent.to_string(context.config)));
+ }
let line_width = last_line_width(&result);
// This checked_sub may fail as the extra space after '=' is not taken into account
// In that case the budget is set to 0 which will make ty.rewrite retry on a new line
- let budget = context
- .config
- .max_width()
- .checked_sub(indent.width() + line_width + ";".len())
- .unwrap_or(0);
+ let budget = context.budget(indent.width() + line_width + ";".len());
let type_indent = indent + line_width;
// Try to fit the type on the same line
let ty_str = try_opt!(
let type_indent = indent.block_indent(context.config);
result.push('\n');
result.push_str(&type_indent.to_string(context.config));
- let budget = try_opt!(
- context
- .config
- .max_width()
- .checked_sub(type_indent.width() + ";".len())
- );
+ let budget = context.budget(type_indent.width() + ";".len());
ty.rewrite(context, Shape::legacy(budget, type_indent))
})
);
)
}
-fn rewrite_missing_comment_on_field(
- context: &RewriteContext,
- shape: Shape,
- lo: BytePos,
- hi: BytePos,
- result: &mut String,
-) -> Option<String> {
- let possibly_comment_snippet = context.snippet(mk_sp(lo, hi));
- let newline_index = possibly_comment_snippet.find('\n');
- let comment_index = possibly_comment_snippet.find('/');
- match (newline_index, comment_index) {
- (Some(i), Some(j)) if i > j => result.push(' '),
- _ => {
- result.push('\n');
- result.push_str(&shape.indent.to_string(context.config));
- }
- }
- let trimmed = possibly_comment_snippet.trim();
- if trimmed.is_empty() {
- None
- } else {
- rewrite_comment(trimmed, false, shape, context.config).map(|s| {
- format!("{}\n{}", s, shape.indent.to_string(context.config))
- })
- }
-}
-
pub fn rewrite_struct_field_prefix(
context: &RewriteContext,
field: &ast::StructField,
- shape: Shape,
) -> Option<String> {
let vis = format_visibility(&field.vis);
- let mut attr_str = try_opt!(
- field
- .attrs
- .rewrite(context, Shape::indented(shape.indent, context.config))
- );
- // Try format missing comments after attributes
- let missing_comment = if !field.attrs.is_empty() {
- rewrite_missing_comment_on_field(
- context,
- shape,
- field.attrs[field.attrs.len() - 1].span.hi,
- field.span.lo,
- &mut attr_str,
- ).unwrap_or(String::new())
- } else {
- String::new()
- };
-
let type_annotation_spacing = type_annotation_spacing(context.config);
Some(match field.ident {
- Some(name) => format!(
- "{}{}{}{}{}:",
- attr_str,
- missing_comment,
- vis,
- name,
- type_annotation_spacing.0
- ),
- None => format!("{}{}{}", attr_str, missing_comment, vis),
+ Some(name) => format!("{}{}{}:", vis, name, type_annotation_spacing.0),
+ None => format!("{}", vis),
})
}
lhs_max_width: usize,
) -> Option<String> {
if contains_skip(&field.attrs) {
- let span = context.snippet(mk_sp(field.attrs[0].span.lo, field.span.hi));
+ let span = context.snippet(mk_sp(field.attrs[0].span.lo(), field.span.hi()));
return wrap_str(span, context.config.max_width(), shape);
}
let type_annotation_spacing = type_annotation_spacing(context.config);
- let prefix = try_opt!(rewrite_struct_field_prefix(context, field, shape));
-
- // Try to put everything on a single line.
- let last_line_width = last_line_width(&prefix);
+ let prefix = try_opt!(rewrite_struct_field_prefix(context, field));
+
+ let attrs_str = try_opt!(field.attrs.rewrite(context, shape));
+ let attrs_extendable = attrs_str.is_empty()
+ || (context.config.attributes_on_same_line_as_field()
+ && is_attributes_extendable(&attrs_str));
+ let missing_span = if field.attrs.is_empty() {
+ mk_sp(field.span.lo(), field.span.lo())
+ } else {
+ mk_sp(field.attrs.last().unwrap().span.hi(), field.span.lo())
+ };
let mut spacing = String::from(if field.ident.is_some() {
type_annotation_spacing.1
} else {
""
});
- let lhs_offset = lhs_max_width.checked_sub(last_line_width).unwrap_or(0);
+ // Try to put everything on a single line.
+ let attr_prefix = try_opt!(combine_strs_with_missing_comments(
+ context,
+ &attrs_str,
+ &prefix,
+ missing_span,
+ shape,
+ attrs_extendable,
+ ));
+ let overhead = last_line_width(&attr_prefix);
+ let lhs_offset = lhs_max_width.checked_sub(overhead).unwrap_or(0);
for _ in 0..lhs_offset {
spacing.push(' ');
}
- let ty_rewritten = rewrite_struct_field_type(context, last_line_width, field, &spacing, shape);
+ // In this extreme case we will be missing a space betweeen an attribute and a field.
+ if prefix.is_empty() && !attrs_str.is_empty() && attrs_extendable && spacing.is_empty() {
+ spacing.push(' ');
+ }
+ let ty_rewritten = rewrite_struct_field_type(context, overhead, field, &spacing, shape);
if let Some(ref ty) = ty_rewritten {
if !ty.contains('\n') {
- return Some(prefix + &ty);
+ return Some(attr_prefix + ty);
}
}
// We must use multiline.
+ let last_line_width = last_line_width(&prefix);
+ let ty_rewritten = rewrite_struct_field_type(context, last_line_width, field, &spacing, shape);
+
let type_offset = shape.indent.block_indent(context.config);
let rewrite_type_in_next_line = || {
field
.rewrite(context, Shape::indented(type_offset, context.config))
};
- match ty_rewritten {
+ let field_str = match ty_rewritten {
// If we start from the next line and type fits in a single line, then do so.
Some(ref ty) => match rewrite_type_in_next_line() {
- Some(ref new_ty) if !new_ty.contains('\n') => Some(format!(
+ Some(ref new_ty) if !new_ty.contains('\n') => format!(
"{}\n{}{}",
prefix,
- type_offset.to_string(&context.config),
+ type_offset.to_string(context.config),
&new_ty
- )),
- _ => Some(prefix + &ty),
+ ),
+ _ => prefix + ty,
},
_ => {
let ty = try_opt!(rewrite_type_in_next_line());
- Some(format!(
+ format!(
"{}\n{}{}",
prefix,
- type_offset.to_string(&context.config),
+ type_offset.to_string(context.config),
&ty
- ))
+ )
}
- }
+ };
+ combine_strs_with_missing_comments(
+ context,
+ &attrs_str,
+ &field_str,
+ missing_span,
+ shape,
+ attrs_extendable,
+ )
}
pub fn rewrite_static(
if let Some(expr) = expr_opt {
let lhs = format!("{}{} =", prefix, ty_str);
// 1 = ;
- let remaining_width = context.config.max_width() - offset.block_indent - 1;
+ let remaining_width = context.budget(offset.block_indent + 1);
rewrite_assign_rhs(
context,
lhs,
expr,
Shape::legacy(remaining_width, offset.block_only()),
- ).and_then(|res| {
- recover_comment_removed(res, span, context, Shape::indented(offset, context.config))
- })
+ ).and_then(|res| recover_comment_removed(res, span, context))
.map(|s| if s.ends_with(';') { s } else { s + ";" })
} else {
Some(format!("{}{};", prefix, ty_str))
let prefix = format!("type {}", ident);
let type_bounds_str = if let Some(ty_param_bounds) = ty_param_bounds_opt {
- let shape = Shape::indented(indent, context.config);
+ // 2 = ": ".len()
+ let shape = try_opt!(Shape::indented(indent, context.config).offset_left(prefix.len() + 2));
let bounds: &[_] = ty_param_bounds;
let bound_str = try_opt!(
bounds
.map(|ty_bound| ty_bound.rewrite(context, shape))
.collect::<Option<Vec<_>>>()
);
- if bounds.len() > 0 {
+ if !bounds.is_empty() {
format!(": {}", join_bounds(context, shape, &bound_str))
} else {
String::new()
let ty_str = try_opt!(ty.rewrite(
context,
Shape::legacy(
- context.config.max_width() - indent.block_indent - prefix.len() - 2,
+ context.budget(indent.block_indent + prefix.len() + 2),
indent.block_only(),
),
));
- Some(format!("{} = {};", prefix, ty_str))
+ Some(format!("{}{} = {};", prefix, type_bounds_str, ty_str))
} else {
Some(format!("{}{};", prefix, type_bounds_str))
}
pub fn span_lo_for_arg(arg: &ast::Arg) -> BytePos {
if is_named_arg(arg) {
- arg.pat.span.lo
+ arg.pat.span.lo()
} else {
- arg.ty.span.lo
+ arg.ty.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,
+ 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(),
}
}
let where_clause = &generics.where_clause;
let mut result = String::with_capacity(1024);
- // Vis unsafety abi.
+ // Vis defaultness constness unsafety abi.
result.push_str(&*format_visibility(vis));
-
- if let ast::Defaultness::Default = defaultness {
- result.push_str("default ");
- }
-
- if let ast::Constness::Const = constness {
- result.push_str("const ");
- }
-
- result.push_str(::utils::format_unsafety(unsafety));
-
+ result.push_str(format_defaultness(defaultness));
+ result.push_str(format_constness(constness));
+ result.push_str(format_unsafety(unsafety));
if abi != abi::Abi::Rust {
- result.push_str(&::utils::format_abi(
- abi,
- context.config.force_explicit_abi(),
- ));
+ result.push_str(&format_abi(abi, context.config.force_explicit_abi()));
}
// fn foo
// 2 = `()`
2
};
- let shape = try_opt!(
- Shape::indented(indent + last_line_width(&result), context.config).sub_width(overhead)
- );
- let g_span = mk_sp(span.lo, fd.output.span().lo);
+ let used_width = last_line_used_width(&result, indent.width());
+ let one_line_budget = context.budget(used_width + overhead);
+ let shape = Shape {
+ width: one_line_budget,
+ indent: indent,
+ offset: used_width,
+ };
+ let g_span = mk_sp(span.lo(), fd.output.span().lo());
let generics_str = try_opt!(rewrite_generics(context, generics, shape, g_span));
result.push_str(&generics_str);
// return type later anyway.
let ret_str = try_opt!(
fd.output
- .rewrite(&context, Shape::indented(indent, context.config))
+ .rewrite(context, Shape::indented(indent, context.config))
);
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 (mut one_line_budget, mut multi_line_budget, mut arg_indent) =
- try_opt!(compute_budgets_for_args(
- context,
- &result,
- indent,
- ret_str_len,
- newline_brace,
- has_braces,
- ));
-
- if context.config.fn_args_layout() == IndentStyle::Block {
- arg_indent = indent.block_indent(context.config);
- // 1 = ","
- multi_line_budget = context.config.max_width() - (arg_indent.width() + 1);
- }
+ let (one_line_budget, multi_line_budget, mut arg_indent) = try_opt!(compute_budgets_for_args(
+ context,
+ &result,
+ indent,
+ ret_str_len,
+ newline_brace,
+ has_braces,
+ multi_line_ret_str,
+ ));
debug!(
"rewrite_fn_base: one_line_budget: {}, multi_line_budget: {}, arg_indent: {:?}",
if one_line_budget == 0 {
if snuggle_angle_bracket {
result.push('(');
+ } else if context.config.fn_args_paren_newline() {
+ result.push('\n');
+ result.push_str(&arg_indent.to_string(context.config));
+ if context.config.fn_args_layout() == IndentStyle::Visual {
+ arg_indent = arg_indent + 1; // extra space for `(`
+ }
+ result.push('(');
} else {
- if context.config.fn_args_paren_newline() {
+ result.push_str("(");
+ if context.config.fn_args_layout() == IndentStyle::Visual {
result.push('\n');
result.push_str(&arg_indent.to_string(context.config));
- if context.config.fn_args_layout() == IndentStyle::Visual {
- arg_indent = arg_indent + 1; // extra space for `(`
- }
- result.push('(');
- } else {
- result.push_str("(");
- if context.config.fn_args_layout() == IndentStyle::Visual {
- result.push('\n');
- result.push_str(&arg_indent.to_string(context.config));
- }
}
}
} else {
result.push('(');
}
- if context.config.spaces_within_parens() && fd.inputs.len() > 0 && result.ends_with('(') {
+ if context.config.spaces_within_parens() && !fd.inputs.is_empty() && result.ends_with('(') {
result.push(' ')
}
- if multi_line_ret_str {
- one_line_budget = 0;
- }
-
// A conservative estimation, to goal is to be over all parens in generics
let args_start = generics
.ty_params
.last()
- .map_or(span.lo, |tp| end_typaram(tp));
+ .map_or(span.lo(), |tp| end_typaram(tp));
let args_end = if fd.inputs.is_empty() {
- context.codemap.span_after(mk_sp(args_start, span.hi), ")")
+ context
+ .codemap
+ .span_after(mk_sp(args_start, span.hi()), ")")
} else {
- let last_span = mk_sp(fd.inputs[fd.inputs.len() - 1].span().hi, span.hi);
+ let last_span = mk_sp(fd.inputs[fd.inputs.len() - 1].span().hi(), span.hi());
context.codemap.span_after(last_span, ")")
};
let args_span = mk_sp(
- context.codemap.span_after(mk_sp(args_start, span.hi), "("),
+ context
+ .codemap
+ .span_after(mk_sp(args_start, span.hi()), "("),
args_end,
);
let arg_str = try_opt!(rewrite_args(
generics_str.contains('\n'),
));
- let multi_line_arg_str =
- arg_str.contains('\n') || arg_str.chars().last().map_or(false, |c| c == ',');
-
let put_args_in_block = match context.config.fn_args_layout() {
- IndentStyle::Block => multi_line_arg_str || generics_str.contains('\n'),
+ IndentStyle::Block => arg_str.contains('\n') || arg_str.len() > one_line_budget,
_ => false,
} && !fd.inputs.is_empty();
result.push(')');
} else {
result.push_str(&arg_str);
- if context.config.spaces_within_parens() && fd.inputs.len() > 0 {
+ 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 = `)`
+ if fd.inputs.is_empty() && used_width + 1 > context.config.max_width() {
+ result.push('\n');
+ }
+ if context.config.spaces_within_parens() && !fd.inputs.is_empty() {
result.push(' ')
}
// If the last line of args contains comment, we cannot put the closing paren
}
// Return type.
- if !ret_str.is_empty() {
+ if let ast::FunctionRetTy::Ty(..) = fd.output {
let ret_should_indent = match context.config.fn_args_layout() {
// If our args are block layout then we surely must have space.
- IndentStyle::Block if put_args_in_block => false,
+ IndentStyle::Block if put_args_in_block || fd.inputs.is_empty() => false,
+ _ if args_last_line_contains_comment => false,
+ _ if result.contains('\n') || multi_line_ret_str => true,
_ => {
- // If we've already gone multi-line, or 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.
+ // 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.
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
sig_length += 2;
}
- let overlong_sig = sig_length > context.config.max_width();
-
- (!args_last_line_contains_comment) &&
- (result.contains('\n') || multi_line_ret_str || overlong_sig)
+ sig_length > context.config.max_width()
}
};
let ret_indent = if ret_should_indent {
}
// Comment between return type and the end of the decl.
- let snippet_lo = fd.output.span().hi;
+ let snippet_lo = fd.output.span().hi();
if where_clause.predicates.is_empty() {
- let snippet_hi = span.hi;
+ let snippet_hi = span.hi();
let snippet = context.snippet(mk_sp(snippet_lo, snippet_hi));
// Try to preserve the layout of the original snippet.
let original_starts_with_newline = snippet
force_new_line_for_brace = true;
}
}
- } else {
- // FIXME it would be nice to catch comments between the return type
- // and the where clause, but we don't have a span for the where
- // clause.
}
}
let should_compress_where = match context.config.where_density() {
- Density::Compressed => !result.contains('\n') || put_args_in_block,
+ Density::Compressed => !result.contains('\n'),
Density::CompressedIfEmpty => !has_body && !result.contains('\n'),
_ => false,
- } || (put_args_in_block && ret_str.is_empty());
+ };
let pos_before_where = match fd.output {
- ast::FunctionRetTy::Default(..) => args_span.hi,
- ast::FunctionRetTy::Ty(ref ty) => ty.span.hi,
+ ast::FunctionRetTy::Default(..) => args_span.hi(),
+ ast::FunctionRetTy::Ty(ref ty) => ty.span.hi(),
};
+
if where_clause.predicates.len() == 1 && should_compress_where {
- let budget = try_opt!(
- context
- .config
- .max_width()
- .checked_sub(last_line_width(&result))
- );
+ let budget = context.budget(last_line_used_width(&result, indent.width()));
if let Some(where_clause_str) = rewrite_where_clause(
context,
where_clause,
Shape::legacy(budget, indent),
Density::Compressed,
"{",
- !has_braces,
- put_args_in_block && ret_str.is_empty(),
- Some(span.hi),
- span,
+ Some(span.hi()),
pos_before_where,
+ WhereClauseOption::compressed(),
) {
- if !where_clause_str.contains('\n') {
- if last_line_width(&result) + where_clause_str.len() > context.config.max_width() {
- result.push('\n');
- }
-
- result.push_str(&where_clause_str);
-
- force_new_line_for_brace |= last_line_contains_single_line_comment(&result);
- return Some((result, force_new_line_for_brace));
- }
+ result.push_str(&where_clause_str);
+ force_new_line_for_brace |= last_line_contains_single_line_comment(&result);
+ return Some((result, force_new_line_for_brace));
}
}
+ let option = WhereClauseOption::new(!has_braces, put_args_in_block && ret_str.is_empty());
let where_clause_str = try_opt!(rewrite_where_clause(
context,
where_clause,
Shape::indented(indent, context.config),
Density::Tall,
"{",
- !has_braces,
- put_args_in_block && ret_str.is_empty(),
- Some(span.hi),
- span,
+ Some(span.hi()),
pos_before_where,
+ option,
));
+ // If there are neither where clause nor return type, we may be missing comments between
+ // args 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()),
+ shape,
+ context,
+ last_line_width(&result),
+ ) {
+ Some(ref missing_comment) if !missing_comment.is_empty() => {
+ result.push_str(missing_comment);
+ force_new_line_for_brace = true;
+ }
+ _ => (),
+ }
+ }
+ }
result.push_str(&where_clause_str);
force_new_line_for_brace |= last_line_contains_single_line_comment(&result);
- return Some((result, force_new_line_for_brace));
+ Some((result, force_new_line_for_brace))
}
-fn last_line_contains_single_line_comment(s: &str) -> bool {
- s.lines().last().map_or(false, |l| l.contains("//"))
+#[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
+}
+
+impl WhereClauseOption {
+ pub fn new(suppress_comma: bool, snuggle: bool) -> WhereClauseOption {
+ WhereClauseOption {
+ suppress_comma: suppress_comma,
+ snuggle: snuggle,
+ compress_where: false,
+ }
+ }
+
+ pub fn compressed() -> WhereClauseOption {
+ WhereClauseOption {
+ suppress_comma: true,
+ snuggle: false,
+ compress_where: true,
+ }
+ }
+
+ pub fn snuggled(current: &str) -> WhereClauseOption {
+ WhereClauseOption {
+ suppress_comma: false,
+ snuggle: trimmed_last_line_width(current) == 1,
+ compress_where: false,
+ }
+ }
}
fn rewrite_args(
let mut arg_item_strs = try_opt!(
args.iter()
.map(|arg| {
- arg.rewrite(&context, Shape::legacy(multi_line_budget, arg_indent))
+ arg.rewrite(context, Shape::legacy(multi_line_budget, arg_indent))
})
.collect::<Option<Vec<_>>>()
);
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
+ args[1].pat.span.lo()
} else {
- args[1].ty.span.lo
+ args[1].ty.span.lo()
};
- let reduced_span = mk_sp(span.lo, second_arg_start);
+ let reduced_span = mk_sp(span.lo(), second_arg_start);
context.codemap.span_after_last(reduced_span, ",")
} else {
- span.lo
+ span.lo()
};
enum ArgumentKind<'a> {
}
let variadic_arg = if variadic {
- let variadic_span = mk_sp(args.last().unwrap().ty.span.hi, span.hi);
+ let variadic_span = mk_sp(args.last().unwrap().ty.span.hi(), span.hi());
let variadic_start = context.codemap.span_after(variadic_span, "...") - BytePos(3);
Some(ArgumentKind::Variadic(variadic_start))
} else {
ArgumentKind::Variadic(start) => start,
},
|arg| match *arg {
- ArgumentKind::Regular(arg) => arg.ty.span.hi,
+ ArgumentKind::Regular(arg) => arg.ty.span.hi(),
ArgumentKind::Variadic(start) => start + BytePos(3),
},
|arg| match *arg {
ArgumentKind::Variadic(..) => Some("...".to_owned()),
},
comment_span_start,
- span.hi,
+ span.hi(),
+ false,
);
arg_items.extend(more_items);
}
- let fits_in_one_line = !generics_str_contains_newline &&
- (arg_items.len() == 0 || arg_items.len() == 1 && arg_item_strs[0].len() <= one_line_budget);
+ 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);
let tactic = definitive_tactic(
&arg_items,
context.config.fn_args_density().to_list_tactic(),
+ Separator::Comma,
one_line_budget,
);
let budget = match tactic {
} else {
trailing_comma
},
+ separator_place: SeparatorPlace::Back,
shape: Shape::legacy(budget, indent),
ends_with_newline: tactic.ends_with_newline(context.config.fn_args_layout()),
preserve_newline: true,
ret_str_len: usize,
newline_brace: bool,
has_braces: bool,
+ force_vertical_layout: bool,
) -> Option<((usize, usize, Indent))> {
debug!(
"compute_budgets_for_args {} {:?}, {}, {}",
newline_brace
);
// Try keeping everything on the same line.
- if !result.contains('\n') {
+ 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;
// 1 = `;`
used_space += 1;
}
- let one_line_budget = context
- .config
- .max_width()
- .checked_sub(used_space)
- .unwrap_or(0);
+ let one_line_budget = context.budget(used_space);
if one_line_budget > 0 {
// 4 = "() {".len()
- let multi_line_overhead =
- indent.width() + result.len() + if newline_brace { 2 } else { 4 };
- let multi_line_budget =
- try_opt!(context.config.max_width().checked_sub(multi_line_overhead));
-
- return Some((
- one_line_budget,
- multi_line_budget,
- indent + result.len() + 1,
- ));
+ let (indent, multi_line_budget) = match context.config.fn_args_layout() {
+ IndentStyle::Block => {
+ let indent = indent.block_indent(context.config);
+ (indent, context.budget(indent.width() + 1))
+ }
+ IndentStyle::Visual => {
+ let indent = indent + result.len() + 1;
+ let multi_line_overhead = indent.width() + if newline_brace { 2 } else { 4 };
+ (indent, context.budget(multi_line_overhead))
+ }
+ };
+
+ return Some((one_line_budget, multi_line_budget, indent));
}
}
// Didn't work. we must force vertical layout and put args on a newline.
let new_indent = indent.block_indent(context.config);
- // Account for `)` and possibly ` {`.
- let used_space = new_indent.width() + if ret_str_len == 0 { 1 } else { 3 };
- let max_space = try_opt!(context.config.max_width().checked_sub(used_space));
- Some((0, max_space, new_indent))
+ let used_space = match context.config.fn_args_layout() {
+ // 1 = `,`
+ IndentStyle::Block => new_indent.width() + 1,
+ // Account for `)` and possibly ` {`.
+ IndentStyle::Visual => new_indent.width() + if ret_str_len == 0 { 1 } else { 3 },
+ };
+ Some((0, context.budget(used_space), new_indent))
}
-fn newline_for_brace(config: &Config, where_clause: &ast::WhereClause) -> bool {
- match config.fn_brace_style() {
- BraceStyle::AlwaysNextLine => true,
- BraceStyle::SameLineWhere if !where_clause.predicates.is_empty() => true,
+fn newline_for_brace(config: &Config, where_clause: &ast::WhereClause, has_body: bool) -> bool {
+ match (config.fn_brace_style(), config.where_density()) {
+ (BraceStyle::AlwaysNextLine, _) => true,
+ (_, Density::Compressed) if where_clause.predicates.len() == 1 => false,
+ (_, Density::CompressedIfEmpty) if where_clause.predicates.len() == 1 && !has_body => false,
+ (BraceStyle::SameLineWhere, _) if !where_clause.predicates.is_empty() => true,
_ => false,
}
}
) -> Option<String> {
// FIXME: convert bounds to where clauses where they get too big or if
// there is a where clause at all.
- let lifetimes: &[_] = &generics.lifetimes;
- let tys: &[_] = &generics.ty_params;
- if lifetimes.is_empty() && tys.is_empty() {
- return Some(String::new());
- }
- // Strings for the generics.
- let lt_strs = lifetimes.iter().map(|lt| lt.rewrite(context, shape));
- let ty_strs = tys.iter().map(|ty_param| ty_param.rewrite(context, shape));
+ // Wrapper type
+ enum GenericsArg<'a> {
+ Lifetime(&'a ast::LifetimeDef),
+ TyParam(&'a ast::TyParam),
+ }
+ impl<'a> Rewrite for GenericsArg<'a> {
+ fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
+ match *self {
+ GenericsArg::Lifetime(ref lifetime) => lifetime.rewrite(context, shape),
+ GenericsArg::TyParam(ref ty) => ty.rewrite(context, shape),
+ }
+ }
+ }
+ impl<'a> Spanned for GenericsArg<'a> {
+ fn span(&self) -> Span {
+ match *self {
+ GenericsArg::Lifetime(ref lifetime) => lifetime.span(),
+ GenericsArg::TyParam(ref ty) => ty.span(),
+ }
+ }
+ }
- // Extract comments between generics.
- let lt_spans = lifetimes.iter().map(|l| {
- let hi = if l.bounds.is_empty() {
- l.lifetime.span.hi
- } else {
- l.bounds[l.bounds.len() - 1].span.hi
- };
- mk_sp(l.lifetime.span.lo, hi)
- });
- let ty_spans = tys.iter().map(|ty| ty.span());
+ if generics.lifetimes.is_empty() && generics.ty_params.is_empty() {
+ return Some(String::new());
+ }
+ let generics_args = generics
+ .lifetimes
+ .iter()
+ .map(|lt| GenericsArg::Lifetime(lt))
+ .chain(generics.ty_params.iter().map(|ty| GenericsArg::TyParam(ty)));
let items = itemize_list(
context.codemap,
- lt_spans.chain(ty_spans).zip(lt_strs.chain(ty_strs)),
+ generics_args,
">",
- |&(sp, _)| sp.lo,
- |&(sp, _)| sp.hi,
- // FIXME: don't clone
- |&(_, ref str)| str.clone(),
+ |arg| arg.span().lo(),
+ |arg| arg.span().hi(),
+ |arg| arg.rewrite(context, shape),
context.codemap.span_after(span, "<"),
- span.hi,
+ span.hi(),
+ false,
);
format_generics_item_list(context, items, shape, one_line_width)
}
{
let item_vec = items.collect::<Vec<_>>();
- let tactic = definitive_tactic(&item_vec, ListTactic::HorizontalVertical, one_line_budget);
+ let tactic = definitive_tactic(
+ &item_vec,
+ ListTactic::HorizontalVertical,
+ Separator::Comma,
+ one_line_budget,
+ );
let fmt = ListFormatting {
tactic: tactic,
separator: ",",
} else {
context.config.trailing_comma()
},
+ separator_place: SeparatorPlace::Back,
shape: shape,
ends_with_newline: tactic.ends_with_newline(context.config.generics_indent()),
preserve_newline: true,
list_str: &str,
list_offset: Indent,
) -> String {
- if context.config.generics_indent() == IndentStyle::Block &&
- (list_str.contains('\n') || list_str.ends_with(','))
+ if context.config.generics_indent() == IndentStyle::Block
+ && (list_str.contains('\n') || list_str.ends_with(','))
{
format!(
"<\n{}{}\n{}>",
let bound_str = try_opt!(
bounds
.iter()
- .map(|ty_bound| ty_bound.rewrite(&context, shape))
+ .map(|ty_bound| ty_bound.rewrite(context, shape))
.collect::<Option<Vec<_>>>()
);
Some(format!(": {}", join_bounds(context, shape, &bound_str)))
where_clause: &ast::WhereClause,
shape: Shape,
terminator: &str,
- suppress_comma: bool,
- // where clause can be kept on the current line.
- snuggle: bool,
span_end: Option<BytePos>,
- span: Span,
span_end_before_where: BytePos,
+ where_clause_option: WhereClauseOption,
) -> Option<String> {
let block_shape = shape.block().with_max_width(context.config);
let (span_before, span_after) =
- missing_span_before_after_where(context, span.hi, span_end_before_where, where_clause);
+ missing_span_before_after_where(span_end_before_where, where_clause);
let (comment_before, comment_after) = try_opt!(rewrite_comments_before_after_where(
context,
span_before,
shape,
));
- let starting_newline = if snuggle && comment_before.is_empty() {
+ let starting_newline = if where_clause_option.snuggle && comment_before.is_empty() {
" ".to_owned()
} else {
"\n".to_owned() + &block_shape.indent.to_string(context.config)
let clause_shape = block_shape.block_indent(context.config.tab_spaces());
// each clause on one line, trailing comma (except if suppress_comma)
- let span_start = where_clause.predicates[0].span().lo;
+ 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.
let len = where_clause.predicates.len();
- let end_of_preds = where_clause.predicates[len - 1].span().hi;
+ let end_of_preds = where_clause.predicates[len - 1].span().hi();
let span_end = span_end.unwrap_or(end_of_preds);
let items = itemize_list(
context.codemap,
where_clause.predicates.iter(),
terminator,
- |pred| pred.span().lo,
- |pred| pred.span().hi,
+ |pred| pred.span().lo(),
+ |pred| pred.span().hi(),
|pred| pred.rewrite(context, block_shape),
span_start,
span_end,
+ false,
);
- let comma_tactic = if suppress_comma {
+ let comma_tactic = if where_clause_option.suppress_comma {
SeparatorTactic::Never
} else {
context.config.trailing_comma()
tactic: DefinitiveListTactic::Vertical,
separator: ",",
trailing_separator: comma_tactic,
+ separator_place: SeparatorPlace::Back,
shape: clause_shape,
ends_with_newline: true,
preserve_newline: true,
};
let preds_str = try_opt!(write_list(&items.collect::<Vec<_>>(), &fmt));
- let newline_before_where = if comment_before.is_empty() || comment_before.ends_with('\n') {
+ let comment_separator = |comment: &str, shape: Shape| if comment.is_empty() {
String::new()
} else {
- "\n".to_owned() + &shape.indent.to_string(context.config)
+ format!("\n{}", shape.indent.to_string(context.config))
};
- let newline_after_where = if comment_after.is_empty() {
- String::new()
+ 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
+ {
+ String::from(" ")
} else {
- "\n".to_owned() + &clause_shape.indent.to_string(context.config)
+ format!("\n{}", clause_shape.indent.to_string(context.config))
};
Some(format!(
- "{}{}{}where{}{}\n{}{}",
+ "{}{}{}where{}{}{}{}",
starting_newline,
comment_before,
newline_before_where,
newline_after_where,
comment_after,
- clause_shape.indent.to_string(context.config),
+ clause_sep,
preds_str
))
}
shape: Shape,
density: Density,
terminator: &str,
- suppress_comma: bool,
- snuggle: bool,
span_end: Option<BytePos>,
- span: Span,
span_end_before_where: BytePos,
+ where_clause_option: WhereClauseOption,
) -> Option<String> {
if where_clause.predicates.is_empty() {
return Some(String::new());
where_clause,
shape,
terminator,
- suppress_comma,
- snuggle,
span_end,
- span,
span_end_before_where,
+ where_clause_option,
);
}
// be out by a char or two.
let budget = context.config.max_width() - offset.width();
- let span_start = where_clause.predicates[0].span().lo;
+ 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.
let len = where_clause.predicates.len();
- let end_of_preds = where_clause.predicates[len - 1].span().hi;
+ let end_of_preds = where_clause.predicates[len - 1].span().hi();
let span_end = span_end.unwrap_or(end_of_preds);
let items = itemize_list(
context.codemap,
where_clause.predicates.iter(),
terminator,
- |pred| pred.span().lo,
- |pred| pred.span().hi,
+ |pred| pred.span().lo(),
+ |pred| pred.span().hi(),
|pred| pred.rewrite(context, Shape::legacy(budget, offset)),
span_start,
span_end,
+ false,
);
let item_vec = items.collect::<Vec<_>>();
// FIXME: we don't need to collect here if the where_layout isn't
// HorizontalVertical.
- let tactic = definitive_tactic(&item_vec, context.config.where_layout(), budget);
+ let tactic = definitive_tactic(
+ &item_vec,
+ context.config.where_layout(),
+ 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.
- if comma_tactic == SeparatorTactic::Vertical || suppress_comma {
+ if comma_tactic == SeparatorTactic::Vertical || where_clause_option.suppress_comma {
comma_tactic = SeparatorTactic::Never;
}
tactic: tactic,
separator: ",",
trailing_separator: comma_tactic,
+ separator_place: SeparatorPlace::Back,
shape: Shape::legacy(budget, offset),
ends_with_newline: tactic.ends_with_newline(context.config.where_pred_indent()),
preserve_newline: true,
} else {
terminator.len()
};
- if density == Density::Tall || preds_str.contains('\n') ||
- shape.indent.width() + " where ".len() + preds_str.len() + end_length > shape.width
+ if density == Density::Tall || preds_str.contains('\n')
+ || shape.indent.width() + " where ".len() + preds_str.len() + end_length > shape.width
{
Some(format!(
"\n{}where {}",
}
fn missing_span_before_after_where(
- context: &RewriteContext,
- item_end: BytePos,
before_item_span_end: BytePos,
where_clause: &ast::WhereClause,
) -> (Span, Span) {
- let snippet = context.snippet(mk_sp(before_item_span_end, item_end));
- let pos_before_where =
- before_item_span_end + BytePos(snippet.find_uncommented("where").unwrap() as u32);
- let missing_span_before = mk_sp(before_item_span_end, pos_before_where);
+ let missing_span_before = mk_sp(before_item_span_end, where_clause.span.lo());
// 5 = `where`
- let pos_after_where = pos_before_where + BytePos(5);
- let missing_span_after = mk_sp(pos_after_where, where_clause.predicates[0].span().lo);
+ let pos_after_where = where_clause.span.lo() + BytePos(5);
+ let missing_span_after = mk_sp(pos_after_where, where_clause.predicates[0].span().lo());
(missing_span_before, missing_span_after)
}
-fn rewrite_missing_comment_in_where(
- context: &RewriteContext,
- comment: &str,
- shape: Shape,
-) -> Option<String> {
- let comment = comment.trim();
- if comment.is_empty() {
- Some(String::new())
- } else {
- rewrite_comment(comment, false, shape, context.config)
- }
-}
-
fn rewrite_comments_before_after_where(
context: &RewriteContext,
span_before_where: Span,
span_after_where: Span,
shape: Shape,
) -> Option<(String, String)> {
- let before_comment = try_opt!(rewrite_missing_comment_in_where(
- context,
- &context.snippet(span_before_where),
- shape,
- ));
- let after_comment = try_opt!(rewrite_missing_comment_in_where(
- context,
- &context.snippet(span_after_where),
+ let before_comment = try_opt!(rewrite_missing_comment(span_before_where, shape, context));
+ let after_comment = try_opt!(rewrite_missing_comment(
+ span_after_where,
shape.block_indent(context.config.tab_spaces()),
+ context,
));
Some((before_comment, after_comment))
}
let mut result = try_opt!(rewrite_generics(context, generics, shape, span));
let same_line_brace = if !generics.where_clause.predicates.is_empty() || result.contains('\n') {
- let budget = context
- .config
- .max_width()
- .checked_sub(last_line_width(&result))
- .unwrap_or(0);
+ let budget = context.budget(last_line_used_width(&result, offset.width()));
+ let option = WhereClauseOption::snuggled(&result);
let where_clause_str = try_opt!(rewrite_where_clause(
context,
&generics.where_clause,
Shape::legacy(budget, offset.block_only()),
Density::Tall,
terminator,
- false,
- trimmed_last_line_width(&result) == 1,
- Some(span.hi),
- span,
- generics.span.hi,
+ Some(span.hi()),
+ generics.span.hi(),
+ option,
));
result.push_str(&where_clause_str);
- force_same_line_brace || brace_style == BraceStyle::PreferSameLine ||
- (generics.where_clause.predicates.is_empty() && trimmed_last_line_width(&result) == 1)
+ force_same_line_brace || brace_style == BraceStyle::PreferSameLine
+ || (generics.where_clause.predicates.is_empty()
+ && trimmed_last_line_width(&result) == 1)
} else {
- force_same_line_brace || trimmed_last_line_width(&result) == 1 ||
- brace_style != BraceStyle::AlwaysNextLine
+ force_same_line_brace || trimmed_last_line_width(&result) == 1
+ || brace_style != BraceStyle::AlwaysNextLine
};
- let total_used_width = if result.contains('\n') {
- last_line_width(&result)
- } else {
- used_width + result.len()
- };
- let remaining_budget = context
- .config
- .max_width()
- .checked_sub(total_used_width)
- .unwrap_or(0);
+ let total_used_width = last_line_used_width(&result, used_width);
+ let remaining_budget = context.budget(total_used_width);
// If the same line brace if forced, it indicates that we are rewriting an item with empty body,
// and hence we take the closer into account as well for one line budget.
// We assume that the closer has the same length as the opener.
Some(result)
}
+
+impl Rewrite for ast::ForeignItem {
+ fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
+ let attrs_str = try_opt!(self.attrs.rewrite(context, shape));
+ // Drop semicolon or it will be interpreted as comment.
+ // FIXME: this may be a faulty span from libsyntax.
+ let span = mk_sp(self.span.lo(), self.span.hi() - BytePos(1));
+
+ let item_str = try_opt!(match self.node {
+ ast::ForeignItemKind::Fn(ref fn_decl, ref generics) => {
+ rewrite_fn_base(
+ context,
+ shape.indent,
+ self.ident,
+ fn_decl,
+ generics,
+ ast::Unsafety::Normal,
+ ast::Constness::NotConst,
+ ast::Defaultness::Final,
+ // These are not actually rust functions,
+ // but we format them as such.
+ abi::Abi::Rust,
+ &self.vis,
+ span,
+ false,
+ false,
+ false,
+ ).map(|(s, _)| format!("{};", s))
+ }
+ ast::ForeignItemKind::Static(ref ty, is_mutable) => {
+ // FIXME(#21): we're dropping potential comments in between the
+ // function keywords here.
+ let vis = format_visibility(&self.vis);
+ let mut_str = if is_mutable { "mut " } else { "" };
+ let prefix = format!("{}static {}{}:", vis, mut_str, self.ident);
+ // 1 = ;
+ let shape = try_opt!(shape.sub_width(1));
+ ty.rewrite(context, shape).map(|ty_str| {
+ // 1 = space between prefix and type.
+ let sep = if prefix.len() + ty_str.len() + 1 <= shape.width {
+ String::from(" ")
+ } else {
+ let nested_indent = shape.indent.block_indent(context.config);
+ format!("\n{}", nested_indent.to_string(context.config))
+ };
+ format!("{}{}{};", prefix, sep, ty_str)
+ })
+ }
+ });
+
+ let missing_span = if self.attrs.is_empty() {
+ mk_sp(self.span.lo(), self.span.lo())
+ } else {
+ mk_sp(self.attrs[self.attrs.len() - 1].span.hi(), self.span.lo())
+ };
+ combine_strs_with_missing_comments(
+ context,
+ &attrs_str,
+ &item_str,
+ missing_span,
+ shape,
+ false,
+ )
+ }
+}