Skip to content

Commit e554d86

Browse files
authored
Merge branch 'master' into imports_indent
2 parents ce5efaf + 1b71956 commit e554d86

File tree

16 files changed

+174
-95
lines changed

16 files changed

+174
-95
lines changed

Diff for: src/bin/main.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ extern crate rustfmt_nightly as rustfmt;
1818
use std::env;
1919
use std::fs::File;
2020
use std::io::{self, stdout, Read, Write};
21-
use std::path::PathBuf;
21+
use std::path::{Path, PathBuf};
2222

2323
use failure::err_msg;
2424

@@ -184,7 +184,7 @@ fn execute(opts: &Options) -> FmtResult<(WriteMode, Summary)> {
184184
Operation::Stdin { input } => {
185185
// try to read config from local directory
186186
let options = CliOptions::from_matches(&matches)?;
187-
let (mut config, _) = load_config(None, Some(&options))?;
187+
let (mut config, _) = load_config(Some(Path::new(".")), Some(&options))?;
188188

189189
// write_mode is always Plain for Stdin.
190190
config.set().write_mode(WriteMode::Plain);

Diff for: src/expr.rs

+18-11
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ pub fn format_expr(
7676
expr.span,
7777
context,
7878
shape,
79-
None,
79+
choose_separator_tactic(context, expr.span),
8080
None,
8181
),
8282
ast::ExprKind::Lit(ref l) => rewrite_literal(context, l, shape),
@@ -1342,6 +1342,18 @@ const SPECIAL_MACRO_WHITELIST: &[(&str, usize)] = &[
13421342
("debug_assert_ne!", 2),
13431343
];
13441344

1345+
fn choose_separator_tactic(context: &RewriteContext, span: Span) -> Option<SeparatorTactic> {
1346+
if context.inside_macro() {
1347+
if span_ends_with_comma(context, span) {
1348+
Some(SeparatorTactic::Always)
1349+
} else {
1350+
Some(SeparatorTactic::Never)
1351+
}
1352+
} else {
1353+
None
1354+
}
1355+
}
1356+
13451357
pub fn rewrite_call(
13461358
context: &RewriteContext,
13471359
callee: &str,
@@ -1356,15 +1368,7 @@ pub fn rewrite_call(
13561368
shape,
13571369
span,
13581370
context.config.width_heuristics().fn_call_width,
1359-
if context.inside_macro() {
1360-
if span_ends_with_comma(context, span) {
1361-
Some(SeparatorTactic::Always)
1362-
} else {
1363-
Some(SeparatorTactic::Never)
1364-
}
1365-
} else {
1366-
None
1367-
},
1371+
choose_separator_tactic(context, span),
13681372
)
13691373
}
13701374

@@ -1442,11 +1446,14 @@ pub fn is_nested_call(expr: &ast::Expr) -> bool {
14421446
pub fn span_ends_with_comma(context: &RewriteContext, span: Span) -> bool {
14431447
let mut result: bool = Default::default();
14441448
let mut prev_char: char = Default::default();
1449+
let closing_delimiters = &[')', '}', ']'];
14451450

14461451
for (kind, c) in CharClasses::new(context.snippet(span).chars()) {
14471452
match c {
14481453
_ if kind.is_comment() || c.is_whitespace() => continue,
1449-
')' | '}' => result = result && prev_char != ')' && prev_char != '}',
1454+
c if closing_delimiters.contains(&c) => {
1455+
result &= !closing_delimiters.contains(&prev_char);
1456+
}
14501457
',' => result = true,
14511458
_ => result = false,
14521459
}

Diff for: src/imports.rs

+24-12
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use syntax::ast::{self, UseTreeKind};
1515
use syntax::codemap::{self, BytePos, Span, DUMMY_SP};
1616

1717
use codemap::SpanUtils;
18+
use comment::combine_strs_with_missing_comments;
1819
use config::IndentStyle;
1920
use lists::{definitive_tactic, itemize_list, write_list, ListFormatting, ListItem, Separator};
2021
use rewrite::{Rewrite, RewriteContext};
@@ -118,6 +119,17 @@ impl PartialEq for UseTree {
118119
}
119120
impl Eq for UseTree {}
120121

122+
impl Spanned for UseTree {
123+
fn span(&self) -> Span {
124+
let lo = if let Some(ref attrs) = self.attrs {
125+
attrs.iter().next().map_or(self.span.lo(), |a| a.span.lo())
126+
} else {
127+
self.span.lo()
128+
};
129+
mk_sp(lo, self.span.hi())
130+
}
131+
}
132+
121133
impl UseSegment {
122134
// Clone a version of self with any top-level alias removed.
123135
fn remove_alias(&self) -> UseSegment {
@@ -219,26 +231,26 @@ impl fmt::Display for UseTree {
219231
impl UseTree {
220232
// Rewrite use tree with `use ` and a trailing `;`.
221233
pub fn rewrite_top_level(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
222-
let mut result = String::with_capacity(256);
223-
if let Some(ref attrs) = self.attrs {
224-
result.push_str(&attrs.rewrite(context, shape)?);
225-
if !result.is_empty() {
226-
result.push_str(&shape.indent.to_string_with_newline(context.config));
227-
}
228-
}
229-
230234
let vis = self.visibility
231235
.as_ref()
232236
.map_or(Cow::from(""), |vis| ::utils::format_visibility(&vis));
233-
result.push_str(&self.rewrite(context, shape.offset_left(vis.len())?)
237+
let use_str = self.rewrite(context, shape.offset_left(vis.len())?)
234238
.map(|s| {
235239
if s.is_empty() {
236240
s.to_owned()
237241
} else {
238242
format!("{}use {};", vis, s)
239243
}
240-
})?);
241-
Some(result)
244+
})?;
245+
if let Some(ref attrs) = self.attrs {
246+
let attr_str = attrs.rewrite(context, shape)?;
247+
let lo = attrs.last().as_ref()?.span().hi();
248+
let hi = self.span.lo();
249+
let span = mk_sp(lo, hi);
250+
combine_strs_with_missing_comments(context, &attr_str, &use_str, span, shape, false)
251+
} else {
252+
Some(use_str)
253+
}
242254
}
243255

244256
// FIXME: Use correct span?
@@ -267,7 +279,7 @@ impl UseTree {
267279
use_tree,
268280
None,
269281
Some(item.vis.clone()),
270-
Some(item.span().lo()),
282+
Some(item.span.lo()),
271283
if item.attrs.is_empty() {
272284
None
273285
} else {

Diff for: src/items.rs

+66-62
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,7 @@ use rewrite::{Rewrite, RewriteContext};
3737
use shape::{Indent, Shape};
3838
use spanned::Spanned;
3939
use types::TraitTyParamBounds;
40-
use utils::{
41-
colon_spaces, contains_skip, first_line_width, format_abi, format_auto, format_constness,
42-
format_defaultness, format_mutability, format_unsafety, format_visibility,
43-
is_attributes_extendable, last_line_contains_single_line_comment, last_line_used_width,
44-
last_line_width, mk_sp, semicolon_for_expr, starts_with_newline, stmt_expr,
45-
trimmed_last_line_width,
46-
};
40+
use utils::*;
4741
use vertical::rewrite_with_alignment;
4842
use visitor::FmtVisitor;
4943

@@ -464,35 +458,39 @@ impl<'a> FmtVisitor<'a> {
464458

465459
self.last_pos = body_start;
466460

467-
self.block_indent = self.block_indent.block_indent(self.config);
468-
let variant_list = self.format_variant_list(enum_def, body_start, span.hi() - BytePos(1));
469-
match variant_list {
470-
Some(ref body_str) => self.push_str(body_str),
471-
None => self.format_missing_no_indent(span.hi() - BytePos(1)),
472-
}
473-
self.block_indent = self.block_indent.block_unindent(self.config);
474-
475-
if variant_list.is_some() || contains_comment(&enum_snippet[brace_pos..]) {
476-
let indent_str = self.block_indent.to_string(self.config);
477-
self.push_str(&indent_str);
461+
match self.format_variant_list(enum_def, body_start, span.hi()) {
462+
Some(ref s) if enum_def.variants.is_empty() => self.push_str(s),
463+
rw => {
464+
self.push_rewrite(mk_sp(body_start, span.hi()), rw);
465+
self.block_indent = self.block_indent.block_unindent(self.config);
466+
}
478467
}
479-
self.push_str("}");
480-
self.last_pos = span.hi();
481468
}
482469

483470
// Format the body of an enum definition
484471
fn format_variant_list(
485-
&self,
472+
&mut self,
486473
enum_def: &ast::EnumDef,
487474
body_lo: BytePos,
488475
body_hi: BytePos,
489476
) -> Option<String> {
490477
if enum_def.variants.is_empty() {
491-
return None;
478+
let mut buffer = String::with_capacity(128);
479+
// 1 = "}"
480+
let span = mk_sp(body_lo, body_hi - BytePos(1));
481+
format_empty_struct_or_tuple(
482+
&self.get_context(),
483+
span,
484+
self.block_indent,
485+
&mut buffer,
486+
"",
487+
"}",
488+
);
489+
return Some(buffer);
492490
}
493491
let mut result = String::with_capacity(1024);
494-
let indentation = self.block_indent.to_string_with_newline(self.config);
495-
result.push_str(&indentation);
492+
let original_offset = self.block_indent;
493+
self.block_indent = self.block_indent.block_indent(self.config);
496494

497495
let itemize_list_with = |one_line_width: usize| {
498496
itemize_list(
@@ -537,7 +535,8 @@ impl<'a> FmtVisitor<'a> {
537535

538536
let list = write_list(&items, &fmt)?;
539537
result.push_str(&list);
540-
result.push('\n');
538+
result.push_str(&original_offset.to_string_with_newline(self.config));
539+
result.push('}');
541540
Some(result)
542541
}
543542

@@ -1201,18 +1200,8 @@ pub fn format_struct_struct(
12011200
}
12021201

12031202
if fields.is_empty() {
1204-
let snippet = context.snippet(mk_sp(body_lo, span.hi() - BytePos(1)));
1205-
if snippet.trim().is_empty() {
1206-
// `struct S {}`
1207-
} else if snippet.trim_right_matches(&[' ', '\t'][..]).ends_with('\n') {
1208-
// fix indent
1209-
result.push_str(snippet.trim_right());
1210-
result.push('\n');
1211-
result.push_str(&offset.to_string(context.config));
1212-
} else {
1213-
result.push_str(snippet);
1214-
}
1215-
result.push('}');
1203+
let inner_span = mk_sp(body_lo, span.hi() - BytePos(1));
1204+
format_empty_struct_or_tuple(context, inner_span, offset, &mut result, "", "}");
12161205
return Some(result);
12171206
}
12181207

@@ -1253,6 +1242,41 @@ fn get_bytepos_after_visibility(vis: &ast::Visibility, default_span: Span) -> By
12531242
}
12541243
}
12551244

1245+
// Format tuple or struct without any fields. We need to make sure that the comments
1246+
// inside the delimiters are preserved.
1247+
fn format_empty_struct_or_tuple(
1248+
context: &RewriteContext,
1249+
span: Span,
1250+
offset: Indent,
1251+
result: &mut String,
1252+
opener: &str,
1253+
closer: &str,
1254+
) {
1255+
// 3 = " {}" or "();"
1256+
let used_width = last_line_used_width(&result, offset.width()) + 3;
1257+
if used_width > context.config.max_width() {
1258+
result.push_str(&offset.to_string_with_newline(context.config))
1259+
}
1260+
result.push_str(opener);
1261+
match rewrite_missing_comment(span, Shape::indented(offset, context.config), context) {
1262+
Some(ref s) if s.is_empty() => (),
1263+
Some(ref s) => {
1264+
if !is_single_line(s) || first_line_contains_single_line_comment(s) {
1265+
let nested_indent_str = offset
1266+
.block_indent(context.config)
1267+
.to_string_with_newline(context.config);
1268+
result.push_str(&nested_indent_str);
1269+
}
1270+
result.push_str(s);
1271+
if last_line_contains_single_line_comment(s) {
1272+
result.push_str(&offset.to_string_with_newline(context.config));
1273+
}
1274+
}
1275+
None => result.push_str(context.snippet(span)),
1276+
}
1277+
result.push_str(closer);
1278+
}
1279+
12561280
fn format_tuple_struct(
12571281
context: &RewriteContext,
12581282
struct_parts: &StructParts,
@@ -1316,31 +1340,11 @@ fn format_tuple_struct(
13161340
};
13171341

13181342
if fields.is_empty() {
1319-
// 3 = `();`
1320-
let used_width = last_line_used_width(&result, offset.width()) + 3;
1321-
if used_width > context.config.max_width() {
1322-
result.push('\n');
1323-
result.push_str(&offset
1324-
.block_indent(context.config)
1325-
.to_string(context.config))
1326-
}
1327-
result.push('(');
1328-
let snippet = context.snippet(mk_sp(
1329-
body_lo,
1330-
context
1331-
.snippet_provider
1332-
.span_before(mk_sp(body_lo, span.hi()), ")"),
1333-
));
1334-
if snippet.is_empty() {
1335-
// `struct S ()`
1336-
} else if snippet.trim_right_matches(&[' ', '\t'][..]).ends_with('\n') {
1337-
result.push_str(snippet.trim_right());
1338-
result.push('\n');
1339-
result.push_str(&offset.to_string(context.config));
1340-
} else {
1341-
result.push_str(snippet);
1342-
}
1343-
result.push(')');
1343+
let body_hi = context
1344+
.snippet_provider
1345+
.span_before(mk_sp(body_lo, span.hi()), ")");
1346+
let inner_span = mk_sp(body_lo, body_hi);
1347+
format_empty_struct_or_tuple(context, inner_span, offset, &mut result, "(", ")");
13441348
} else {
13451349
let shape = Shape::indented(offset, context.config).sub_width(1)?;
13461350
let fields = &fields.iter().collect::<Vec<_>>();

Diff for: src/reorder.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -128,8 +128,8 @@ fn rewrite_reorderable_items(
128128
cloned.iter(),
129129
"",
130130
";",
131-
|item| item.span.lo(),
132-
|item| item.span.hi(),
131+
|item| item.span().lo(),
132+
|item| item.span().hi(),
133133
|_item| Some("".to_owned()),
134134
span.lo(),
135135
span.hi(),

Diff for: src/utils.rs

+10
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,16 @@ pub fn outer_attributes(attrs: &[ast::Attribute]) -> Vec<ast::Attribute> {
136136
filter_attributes(attrs, ast::AttrStyle::Outer)
137137
}
138138

139+
#[inline]
140+
pub fn is_single_line(s: &str) -> bool {
141+
s.chars().find(|&c| c == '\n').is_none()
142+
}
143+
144+
#[inline]
145+
pub fn first_line_contains_single_line_comment(s: &str) -> bool {
146+
s.lines().next().map_or(false, |l| l.contains("//"))
147+
}
148+
139149
#[inline]
140150
pub fn last_line_contains_single_line_comment(s: &str) -> bool {
141151
s.lines().last().map_or(false, |l| l.contains("//"))

Diff for: tests/source/enum.rs

+4
Original file line numberDiff line numberDiff line change
@@ -192,3 +192,7 @@ pub enum QlError {
192192
// (kind, input, expected)
193193
#[fail(display = "Could not find {}: Found: {}, expected: {:?}", 0, 1, 2)] ResolveError(&'static str, String, Option<String>),
194194
}
195+
196+
// #2594
197+
enum Foo {}
198+
enum Bar { }

Diff for: tests/source/imports.rs

+5
Original file line numberDiff line numberDiff line change
@@ -88,3 +88,8 @@ use a::{b::{c::*}};
8888
use a::{b::{c::{}}};
8989
use a::{b::{c::d}};
9090
use a::{b::{c::{xxx, yyy, zzz}}};
91+
92+
// #2645
93+
/// This line is not affected.
94+
// This line is deleted.
95+
use c;

Diff for: tests/source/macros.rs

+8
Original file line numberDiff line numberDiff line change
@@ -380,3 +380,11 @@ fn foo() {
380380
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);
381381
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,);
382382
}
383+
384+
// #2652
385+
// Preserve trailing comma inside macro, even if it looks an array.
386+
macro_rules! bar {
387+
($m:ident) => {
388+
$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]);
389+
};
390+
}

0 commit comments

Comments
 (0)