Merge branch 'master' into imports_indent

This commit is contained in:
Nick Cameron 2018-04-30 11:50:53 +12:00 committed by GitHub
commit e554d8617d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 174 additions and 95 deletions

View File

@ -18,7 +18,7 @@ extern crate rustfmt_nightly as rustfmt;
use std::env; use std::env;
use std::fs::File; use std::fs::File;
use std::io::{self, stdout, Read, Write}; use std::io::{self, stdout, Read, Write};
use std::path::PathBuf; use std::path::{Path, PathBuf};
use failure::err_msg; use failure::err_msg;
@ -184,7 +184,7 @@ fn execute(opts: &Options) -> FmtResult<(WriteMode, Summary)> {
Operation::Stdin { input } => { Operation::Stdin { input } => {
// try to read config from local directory // try to read config from local directory
let options = CliOptions::from_matches(&matches)?; let options = CliOptions::from_matches(&matches)?;
let (mut config, _) = load_config(None, Some(&options))?; let (mut config, _) = load_config(Some(Path::new(".")), Some(&options))?;
// write_mode is always Plain for Stdin. // write_mode is always Plain for Stdin.
config.set().write_mode(WriteMode::Plain); config.set().write_mode(WriteMode::Plain);

View File

@ -76,7 +76,7 @@ pub fn format_expr(
expr.span, expr.span,
context, context,
shape, shape,
None, choose_separator_tactic(context, expr.span),
None, None,
), ),
ast::ExprKind::Lit(ref l) => rewrite_literal(context, l, shape), ast::ExprKind::Lit(ref l) => rewrite_literal(context, l, shape),
@ -1342,6 +1342,18 @@ const SPECIAL_MACRO_WHITELIST: &[(&str, usize)] = &[
("debug_assert_ne!", 2), ("debug_assert_ne!", 2),
]; ];
fn choose_separator_tactic(context: &RewriteContext, span: Span) -> Option<SeparatorTactic> {
if context.inside_macro() {
if span_ends_with_comma(context, span) {
Some(SeparatorTactic::Always)
} else {
Some(SeparatorTactic::Never)
}
} else {
None
}
}
pub fn rewrite_call( pub fn rewrite_call(
context: &RewriteContext, context: &RewriteContext,
callee: &str, callee: &str,
@ -1356,15 +1368,7 @@ pub fn rewrite_call(
shape, shape,
span, span,
context.config.width_heuristics().fn_call_width, context.config.width_heuristics().fn_call_width,
if context.inside_macro() { choose_separator_tactic(context, span),
if span_ends_with_comma(context, span) {
Some(SeparatorTactic::Always)
} else {
Some(SeparatorTactic::Never)
}
} else {
None
},
) )
} }
@ -1442,11 +1446,14 @@ pub fn is_nested_call(expr: &ast::Expr) -> bool {
pub fn span_ends_with_comma(context: &RewriteContext, span: Span) -> bool { pub fn span_ends_with_comma(context: &RewriteContext, span: Span) -> bool {
let mut result: bool = Default::default(); let mut result: bool = Default::default();
let mut prev_char: char = Default::default(); let mut prev_char: char = Default::default();
let closing_delimiters = &[')', '}', ']'];
for (kind, c) in CharClasses::new(context.snippet(span).chars()) { for (kind, c) in CharClasses::new(context.snippet(span).chars()) {
match c { match c {
_ if kind.is_comment() || c.is_whitespace() => continue, _ if kind.is_comment() || c.is_whitespace() => continue,
')' | '}' => result = result && prev_char != ')' && prev_char != '}', c if closing_delimiters.contains(&c) => {
result &= !closing_delimiters.contains(&prev_char);
}
',' => result = true, ',' => result = true,
_ => result = false, _ => result = false,
} }

View File

@ -15,6 +15,7 @@ use syntax::ast::{self, UseTreeKind};
use syntax::codemap::{self, BytePos, Span, DUMMY_SP}; use syntax::codemap::{self, BytePos, Span, DUMMY_SP};
use codemap::SpanUtils; use codemap::SpanUtils;
use comment::combine_strs_with_missing_comments;
use config::IndentStyle; use config::IndentStyle;
use lists::{definitive_tactic, itemize_list, write_list, ListFormatting, ListItem, Separator}; use lists::{definitive_tactic, itemize_list, write_list, ListFormatting, ListItem, Separator};
use rewrite::{Rewrite, RewriteContext}; use rewrite::{Rewrite, RewriteContext};
@ -118,6 +119,17 @@ impl PartialEq for UseTree {
} }
impl Eq for UseTree {} impl Eq for UseTree {}
impl Spanned for UseTree {
fn span(&self) -> Span {
let lo = if let Some(ref attrs) = self.attrs {
attrs.iter().next().map_or(self.span.lo(), |a| a.span.lo())
} else {
self.span.lo()
};
mk_sp(lo, self.span.hi())
}
}
impl UseSegment { impl UseSegment {
// Clone a version of self with any top-level alias removed. // Clone a version of self with any top-level alias removed.
fn remove_alias(&self) -> UseSegment { fn remove_alias(&self) -> UseSegment {
@ -219,26 +231,26 @@ impl fmt::Display for UseTree {
impl UseTree { impl UseTree {
// Rewrite use tree with `use ` and a trailing `;`. // Rewrite use tree with `use ` and a trailing `;`.
pub fn rewrite_top_level(&self, context: &RewriteContext, shape: Shape) -> Option<String> { pub fn rewrite_top_level(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
let mut result = String::with_capacity(256);
if let Some(ref attrs) = self.attrs {
result.push_str(&attrs.rewrite(context, shape)?);
if !result.is_empty() {
result.push_str(&shape.indent.to_string_with_newline(context.config));
}
}
let vis = self.visibility let vis = self.visibility
.as_ref() .as_ref()
.map_or(Cow::from(""), |vis| ::utils::format_visibility(&vis)); .map_or(Cow::from(""), |vis| ::utils::format_visibility(&vis));
result.push_str(&self.rewrite(context, shape.offset_left(vis.len())?) let use_str = self.rewrite(context, shape.offset_left(vis.len())?)
.map(|s| { .map(|s| {
if s.is_empty() { if s.is_empty() {
s.to_owned() s.to_owned()
} else { } else {
format!("{}use {};", vis, s) format!("{}use {};", vis, s)
} }
})?); })?;
Some(result) if let Some(ref attrs) = self.attrs {
let attr_str = attrs.rewrite(context, shape)?;
let lo = attrs.last().as_ref()?.span().hi();
let hi = self.span.lo();
let span = mk_sp(lo, hi);
combine_strs_with_missing_comments(context, &attr_str, &use_str, span, shape, false)
} else {
Some(use_str)
}
} }
// FIXME: Use correct span? // FIXME: Use correct span?
@ -267,7 +279,7 @@ impl UseTree {
use_tree, use_tree,
None, None,
Some(item.vis.clone()), Some(item.vis.clone()),
Some(item.span().lo()), Some(item.span.lo()),
if item.attrs.is_empty() { if item.attrs.is_empty() {
None None
} else { } else {

View File

@ -37,13 +37,7 @@ use rewrite::{Rewrite, RewriteContext};
use shape::{Indent, Shape}; use shape::{Indent, Shape};
use spanned::Spanned; use spanned::Spanned;
use types::TraitTyParamBounds; use types::TraitTyParamBounds;
use utils::{ use utils::*;
colon_spaces, contains_skip, first_line_width, format_abi, format_auto, 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, starts_with_newline, stmt_expr,
trimmed_last_line_width,
};
use vertical::rewrite_with_alignment; use vertical::rewrite_with_alignment;
use visitor::FmtVisitor; use visitor::FmtVisitor;
@ -464,35 +458,39 @@ impl<'a> FmtVisitor<'a> {
self.last_pos = body_start; self.last_pos = body_start;
self.block_indent = self.block_indent.block_indent(self.config); match self.format_variant_list(enum_def, body_start, span.hi()) {
let variant_list = self.format_variant_list(enum_def, body_start, span.hi() - BytePos(1)); Some(ref s) if enum_def.variants.is_empty() => self.push_str(s),
match variant_list { rw => {
Some(ref body_str) => self.push_str(body_str), self.push_rewrite(mk_sp(body_start, span.hi()), rw);
None => self.format_missing_no_indent(span.hi() - BytePos(1)), self.block_indent = self.block_indent.block_unindent(self.config);
}
} }
self.block_indent = self.block_indent.block_unindent(self.config);
if variant_list.is_some() || contains_comment(&enum_snippet[brace_pos..]) {
let indent_str = self.block_indent.to_string(self.config);
self.push_str(&indent_str);
}
self.push_str("}");
self.last_pos = span.hi();
} }
// Format the body of an enum definition // Format the body of an enum definition
fn format_variant_list( fn format_variant_list(
&self, &mut self,
enum_def: &ast::EnumDef, enum_def: &ast::EnumDef,
body_lo: BytePos, body_lo: BytePos,
body_hi: BytePos, body_hi: BytePos,
) -> Option<String> { ) -> Option<String> {
if enum_def.variants.is_empty() { if enum_def.variants.is_empty() {
return None; let mut buffer = String::with_capacity(128);
// 1 = "}"
let span = mk_sp(body_lo, body_hi - BytePos(1));
format_empty_struct_or_tuple(
&self.get_context(),
span,
self.block_indent,
&mut buffer,
"",
"}",
);
return Some(buffer);
} }
let mut result = String::with_capacity(1024); let mut result = String::with_capacity(1024);
let indentation = self.block_indent.to_string_with_newline(self.config); let original_offset = self.block_indent;
result.push_str(&indentation); self.block_indent = self.block_indent.block_indent(self.config);
let itemize_list_with = |one_line_width: usize| { let itemize_list_with = |one_line_width: usize| {
itemize_list( itemize_list(
@ -537,7 +535,8 @@ impl<'a> FmtVisitor<'a> {
let list = write_list(&items, &fmt)?; let list = write_list(&items, &fmt)?;
result.push_str(&list); result.push_str(&list);
result.push('\n'); result.push_str(&original_offset.to_string_with_newline(self.config));
result.push('}');
Some(result) Some(result)
} }
@ -1201,18 +1200,8 @@ pub fn format_struct_struct(
} }
if fields.is_empty() { if fields.is_empty() {
let snippet = context.snippet(mk_sp(body_lo, span.hi() - BytePos(1))); let inner_span = mk_sp(body_lo, span.hi() - BytePos(1));
if snippet.trim().is_empty() { format_empty_struct_or_tuple(context, inner_span, offset, &mut result, "", "}");
// `struct S {}`
} else if snippet.trim_right_matches(&[' ', '\t'][..]).ends_with('\n') {
// fix indent
result.push_str(snippet.trim_right());
result.push('\n');
result.push_str(&offset.to_string(context.config));
} else {
result.push_str(snippet);
}
result.push('}');
return Some(result); return Some(result);
} }
@ -1253,6 +1242,41 @@ fn get_bytepos_after_visibility(vis: &ast::Visibility, default_span: Span) -> By
} }
} }
// Format tuple or struct without any fields. We need to make sure that the comments
// inside the delimiters are preserved.
fn format_empty_struct_or_tuple(
context: &RewriteContext,
span: Span,
offset: Indent,
result: &mut String,
opener: &str,
closer: &str,
) {
// 3 = " {}" or "();"
let used_width = last_line_used_width(&result, offset.width()) + 3;
if used_width > context.config.max_width() {
result.push_str(&offset.to_string_with_newline(context.config))
}
result.push_str(opener);
match rewrite_missing_comment(span, Shape::indented(offset, context.config), context) {
Some(ref s) if s.is_empty() => (),
Some(ref s) => {
if !is_single_line(s) || first_line_contains_single_line_comment(s) {
let nested_indent_str = offset
.block_indent(context.config)
.to_string_with_newline(context.config);
result.push_str(&nested_indent_str);
}
result.push_str(s);
if last_line_contains_single_line_comment(s) {
result.push_str(&offset.to_string_with_newline(context.config));
}
}
None => result.push_str(context.snippet(span)),
}
result.push_str(closer);
}
fn format_tuple_struct( fn format_tuple_struct(
context: &RewriteContext, context: &RewriteContext,
struct_parts: &StructParts, struct_parts: &StructParts,
@ -1316,31 +1340,11 @@ fn format_tuple_struct(
}; };
if fields.is_empty() { if fields.is_empty() {
// 3 = `();` let body_hi = context
let used_width = last_line_used_width(&result, offset.width()) + 3; .snippet_provider
if used_width > context.config.max_width() { .span_before(mk_sp(body_lo, span.hi()), ")");
result.push('\n'); let inner_span = mk_sp(body_lo, body_hi);
result.push_str(&offset format_empty_struct_or_tuple(context, inner_span, offset, &mut result, "(", ")");
.block_indent(context.config)
.to_string(context.config))
}
result.push('(');
let snippet = context.snippet(mk_sp(
body_lo,
context
.snippet_provider
.span_before(mk_sp(body_lo, span.hi()), ")"),
));
if snippet.is_empty() {
// `struct S ()`
} else if snippet.trim_right_matches(&[' ', '\t'][..]).ends_with('\n') {
result.push_str(snippet.trim_right());
result.push('\n');
result.push_str(&offset.to_string(context.config));
} else {
result.push_str(snippet);
}
result.push(')');
} else { } else {
let shape = Shape::indented(offset, context.config).sub_width(1)?; let shape = Shape::indented(offset, context.config).sub_width(1)?;
let fields = &fields.iter().collect::<Vec<_>>(); let fields = &fields.iter().collect::<Vec<_>>();

View File

@ -128,8 +128,8 @@ fn rewrite_reorderable_items(
cloned.iter(), cloned.iter(),
"", "",
";", ";",
|item| item.span.lo(), |item| item.span().lo(),
|item| item.span.hi(), |item| item.span().hi(),
|_item| Some("".to_owned()), |_item| Some("".to_owned()),
span.lo(), span.lo(),
span.hi(), span.hi(),

View File

@ -136,6 +136,16 @@ pub fn outer_attributes(attrs: &[ast::Attribute]) -> Vec<ast::Attribute> {
filter_attributes(attrs, ast::AttrStyle::Outer) filter_attributes(attrs, ast::AttrStyle::Outer)
} }
#[inline]
pub fn is_single_line(s: &str) -> bool {
s.chars().find(|&c| c == '\n').is_none()
}
#[inline]
pub fn first_line_contains_single_line_comment(s: &str) -> bool {
s.lines().next().map_or(false, |l| l.contains("//"))
}
#[inline] #[inline]
pub fn last_line_contains_single_line_comment(s: &str) -> bool { pub fn last_line_contains_single_line_comment(s: &str) -> bool {
s.lines().last().map_or(false, |l| l.contains("//")) s.lines().last().map_or(false, |l| l.contains("//"))

View File

@ -192,3 +192,7 @@ pub enum QlError {
// (kind, input, expected) // (kind, input, expected)
#[fail(display = "Could not find {}: Found: {}, expected: {:?}", 0, 1, 2)] ResolveError(&'static str, String, Option<String>), #[fail(display = "Could not find {}: Found: {}, expected: {:?}", 0, 1, 2)] ResolveError(&'static str, String, Option<String>),
} }
// #2594
enum Foo {}
enum Bar { }

View File

@ -88,3 +88,8 @@ use a::{b::{c::*}};
use a::{b::{c::{}}}; use a::{b::{c::{}}};
use a::{b::{c::d}}; use a::{b::{c::d}};
use a::{b::{c::{xxx, yyy, zzz}}}; use a::{b::{c::{xxx, yyy, zzz}}};
// #2645
/// This line is not affected.
// This line is deleted.
use c;

View File

@ -380,3 +380,11 @@ fn foo() {
foo!(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); foo!(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1);
foo!(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,); foo!(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,);
} }
// #2652
// Preserve trailing comma inside macro, even if it looks an array.
macro_rules! bar {
($m:ident) => {
$m!([a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z]);
};
}

View File

@ -255,8 +255,12 @@ struct Foo {
struct Foo { struct Foo {
// trailing space -> // trailing space ->
} }
struct Foo { /* comment */ } struct Foo {
struct Foo( /* comment */ ); // comment
}
struct Foo(
// comment
);
struct LongStruct { struct LongStruct {
a: A, a: A,

View File

@ -258,3 +258,7 @@ pub enum QlError {
#[fail(display = "Could not find {}: Found: {}, expected: {:?}", 0, 1, 2)] #[fail(display = "Could not find {}: Found: {}, expected: {:?}", 0, 1, 2)]
ResolveError(&'static str, String, Option<String>), ResolveError(&'static str, String, Option<String>),
} }
// #2594
enum Foo {}
enum Bar {}

View File

@ -110,3 +110,8 @@ use fooo::{
use a::b::c::d; use a::b::c::d;
use a::b::c::*; use a::b::c::*;
use a::b::c::{xxx, yyy, zzz}; use a::b::c::{xxx, yyy, zzz};
// #2645
/// This line is not affected.
// This line is deleted.
use c;

View File

@ -4,7 +4,9 @@
trait NameC { trait NameC {
// comment // comment
} }
struct FooC { /* comment */ } struct FooC {
// comment
}
enum MooC { enum MooC {
// comment // comment
} }

View File

@ -961,3 +961,11 @@ fn foo() {
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
); );
} }
// #2652
// Preserve trailing comma inside macro, even if it looks an array.
macro_rules! bar {
($m:ident) => {
$m!([a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z]);
};
}

View File

@ -228,8 +228,12 @@ struct Foo {
struct Foo { struct Foo {
// trailing space -> // trailing space ->
} }
struct Foo { /* comment */ } struct Foo {
struct Foo( /* comment */ ); // comment
}
struct Foo(
// comment
);
struct LongStruct { struct LongStruct {
a: A, a: A,

View File

@ -136,7 +136,9 @@ union Foo {
union Foo { union Foo {
// trailing space -> // trailing space ->
} }
union Foo { /* comment */ } union Foo {
// comment
}
union LongUnion { union LongUnion {
a: A, a: A,