Skip to content

Commit 45c0b47

Browse files
authored
Merge pull request #2703 from nrc/attrs
Use scoped attributes for skip attribute
2 parents 634ca02 + c977c2c commit 45c0b47

38 files changed

+196
-101
lines changed

.travis.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,7 @@ matrix:
2828
- env: INTEGRATION=futures-rs
2929
- env: INTEGRATION=rand
3030
- env: INTEGRATION=failure
31-
- env: INTEGRATION=glob
3231
- env: INTEGRATION=error-chain
33-
- env: INTEGRATION=tempdir
3432
- env: INTEGRATION=bitflags
3533
- env: INTEGRATION=log
3634
allow_failures:
@@ -47,6 +45,8 @@ matrix:
4745
- env: INTEGRATION=futures-rs
4846
- env: INTEGRATION=log
4947
- env: INTEGRATION=rand
48+
- env: INTEGRATION=glob
49+
- env: INTEGRATION=tempdir
5050

5151
before_script:
5252
- |

Configurations.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -1951,7 +1951,7 @@ lines are found, they are trimmed down to match this integer.
19511951
Original Code:
19521952

19531953
```rust
1954-
#![rustfmt_skip]
1954+
#![rustfmt::skip]
19551955

19561956
fn foo() {
19571957
println!("a");
@@ -2010,7 +2010,7 @@ them, additional blank lines are inserted.
20102010
Original Code (rustfmt will not change it with the default value of `0`):
20112011

20122012
```rust
2013-
#![rustfmt_skip]
2013+
#![rustfmt::skip]
20142014

20152015
fn foo() {
20162016
println!("a");

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ See [Configurations.md](Configurations.md) for details.
174174
* For things you do not want rustfmt to mangle, use one of
175175

176176
```rust
177-
#[rustfmt_skip] // requires nightly and #![feature(custom_attribute)] in crate root
177+
#[rustfmt::skip] // requires nightly Rust and #![feature(tool_attributes)] in crate root
178178
#[cfg_attr(rustfmt, rustfmt_skip)] // works in stable
179179
```
180180
* When you run rustfmt, place a file named `rustfmt.toml` or `.rustfmt.toml` in

rustfmt.toml

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
error_on_line_overflow = true
2+
error_on_unformatted = true

src/attr.rs

+12-9
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use expr::rewrite_literal;
2020
use lists::{itemize_list, write_list, ListFormatting};
2121
use rewrite::{Rewrite, RewriteContext};
2222
use shape::Shape;
23+
use types::{rewrite_path, PathContext};
2324
use utils::{count_newlines, mk_sp};
2425

2526
/// Returns attributes on the given statement.
@@ -200,17 +201,19 @@ fn allow_mixed_tactic_for_nested_metaitem_list(list: &[ast::NestedMetaItem]) ->
200201
impl Rewrite for ast::MetaItem {
201202
fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
202203
Some(match self.node {
203-
ast::MetaItemKind::Word => String::from(&*self.name().as_str()),
204+
ast::MetaItemKind::Word => {
205+
rewrite_path(context, PathContext::Type, None, &self.ident, shape)?
206+
}
204207
ast::MetaItemKind::List(ref list) => {
205-
let name = self.name().as_str();
208+
let path = rewrite_path(context, PathContext::Type, None, &self.ident, shape)?;
206209
let item_shape = match context.config.indent_style() {
207210
IndentStyle::Block => shape
208211
.block_indent(context.config.tab_spaces())
209212
.with_max_width(context.config),
210213
// 1 = `(`, 2 = `]` and `)`
211214
IndentStyle::Visual => shape
212215
.visual_indent(0)
213-
.shrink_left(name.len() + 1)
216+
.shrink_left(path.len() + 1)
214217
.and_then(|s| s.sub_width(2))?,
215218
};
216219
let items = itemize_list(
@@ -248,21 +251,21 @@ impl Rewrite for ast::MetaItem {
248251
};
249252
let item_str = write_list(&item_vec, &fmt)?;
250253
// 3 = "()" and "]"
251-
let one_line_budget = shape.offset_left(name.len())?.sub_width(3)?.width;
254+
let one_line_budget = shape.offset_left(path.len())?.sub_width(3)?.width;
252255
if context.config.indent_style() == IndentStyle::Visual
253256
|| (!item_str.contains('\n') && item_str.len() <= one_line_budget)
254257
{
255-
format!("{}({})", name, item_str)
258+
format!("{}({})", path, item_str)
256259
} else {
257260
let indent = shape.indent.to_string_with_newline(context.config);
258261
let nested_indent = item_shape.indent.to_string_with_newline(context.config);
259-
format!("{}({}{}{})", name, nested_indent, item_str, indent)
262+
format!("{}({}{}{})", path, nested_indent, item_str, indent)
260263
}
261264
}
262265
ast::MetaItemKind::NameValue(ref literal) => {
263-
let name = self.name().as_str();
266+
let path = rewrite_path(context, PathContext::Type, None, &self.ident, shape)?;
264267
// 3 = ` = `
265-
let lit_shape = shape.shrink_left(name.len() + 3)?;
268+
let lit_shape = shape.shrink_left(path.len() + 3)?;
266269
// `rewrite_literal` returns `None` when `literal` exceeds max
267270
// width. Since a literal is basically unformattable unless it
268271
// is a string literal (and only if `format_strings` is set),
@@ -271,7 +274,7 @@ impl Rewrite for ast::MetaItem {
271274
// See #2479 for example.
272275
let value = rewrite_literal(context, literal, lit_shape)
273276
.unwrap_or_else(|| context.snippet(literal.span).to_owned());
274-
format!("{} = {}", name, value)
277+
format!("{} = {}", path, value)
275278
}
276279
})
277280
}

src/comment.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1253,7 +1253,7 @@ mod test {
12531253
}
12541254

12551255
#[test]
1256-
#[cfg_attr(rustfmt, rustfmt_skip)]
1256+
#[rustfmt::skip]
12571257
fn format_comments() {
12581258
let mut config: ::config::Config = Default::default();
12591259
config.set().wrap_comments(true);

src/lib.rs

+59-27
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,9 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
#![feature(custom_attribute)]
11+
#![feature(tool_attributes)]
1212
#![feature(decl_macro)]
13-
// FIXME(cramertj) remove after match_default_bindings merges
14-
#![allow(stable_features)]
1513
#![allow(unused_attributes)]
16-
#![feature(match_default_bindings)]
1714
#![feature(type_ascription)]
1815
#![feature(unicode_internals)]
1916

@@ -40,6 +37,7 @@ extern crate term;
4037
extern crate toml;
4138
extern crate unicode_segmentation;
4239

40+
use std::cell::RefCell;
4341
use std::collections::HashMap;
4442
use std::fmt;
4543
use std::io::{self, stdout, Write};
@@ -50,7 +48,7 @@ use std::time::Duration;
5048

5149
use syntax::ast;
5250
pub use syntax::codemap::FileName;
53-
use syntax::codemap::{CodeMap, FilePathMapping};
51+
use syntax::codemap::{CodeMap, FilePathMapping, Span};
5452
use syntax::errors::emitter::{ColorConfig, EmitterWriter};
5553
use syntax::errors::{DiagnosticBuilder, Handler};
5654
use syntax::parse::{self, ParseSess};
@@ -128,9 +126,14 @@ pub enum ErrorKind {
128126
// License check has failed
129127
#[fail(display = "license check failed")]
130128
LicenseCheck,
129+
// Used deprecated skip attribute
130+
#[fail(display = "`rustfmt_skip` is deprecated; use `rustfmt::skip`")]
131+
DeprecatedAttr,
132+
// Used a rustfmt:: attribute other than skip
133+
#[fail(display = "invalid attribute")]
134+
BadAttr,
131135
}
132136

133-
// Formatting errors that are identified *after* rustfmt has run.
134137
struct FormattingError {
135138
line: usize,
136139
kind: ErrorKind,
@@ -140,11 +143,28 @@ struct FormattingError {
140143
}
141144

142145
impl FormattingError {
146+
fn from_span(span: &Span, codemap: &CodeMap, kind: ErrorKind) -> FormattingError {
147+
FormattingError {
148+
line: codemap.lookup_char_pos(span.lo()).line,
149+
kind,
150+
is_comment: false,
151+
is_string: false,
152+
line_buffer: codemap
153+
.span_to_lines(*span)
154+
.ok()
155+
.and_then(|fl| {
156+
fl.file
157+
.get_line(fl.lines[0].line_index)
158+
.map(|l| l.into_owned())
159+
})
160+
.unwrap_or_else(|| String::new()),
161+
}
162+
}
143163
fn msg_prefix(&self) -> &str {
144164
match self.kind {
145165
ErrorKind::LineOverflow(..) | ErrorKind::TrailingWhitespace => "internal error:",
146-
ErrorKind::LicenseCheck => "error:",
147-
ErrorKind::BadIssue(_) => "warning:",
166+
ErrorKind::LicenseCheck | ErrorKind::BadAttr => "error:",
167+
ErrorKind::BadIssue(_) | ErrorKind::DeprecatedAttr => "warning:",
148168
}
149169
}
150170

@@ -161,7 +181,7 @@ impl FormattingError {
161181
fn format_len(&self) -> (usize, usize) {
162182
match self.kind {
163183
ErrorKind::LineOverflow(found, max) => (max, found - max),
164-
ErrorKind::TrailingWhitespace => {
184+
ErrorKind::TrailingWhitespace | ErrorKind::DeprecatedAttr | ErrorKind::BadAttr => {
165185
let trailing_ws_start = self
166186
.line_buffer
167187
.rfind(|c: char| !c.is_whitespace())
@@ -177,20 +197,30 @@ impl FormattingError {
177197
}
178198
}
179199

200+
#[derive(Clone)]
180201
pub struct FormatReport {
181202
// Maps stringified file paths to their associated formatting errors.
182-
file_error_map: HashMap<FileName, Vec<FormattingError>>,
203+
file_error_map: Rc<RefCell<HashMap<FileName, Vec<FormattingError>>>>,
183204
}
184205

185206
impl FormatReport {
186207
fn new() -> FormatReport {
187208
FormatReport {
188-
file_error_map: HashMap::new(),
209+
file_error_map: Rc::new(RefCell::new(HashMap::new())),
189210
}
190211
}
191212

213+
fn append(&self, f: FileName, mut v: Vec<FormattingError>) {
214+
self.file_error_map
215+
.borrow_mut()
216+
.entry(f)
217+
.and_modify(|fe| fe.append(&mut v))
218+
.or_insert(v);
219+
}
220+
192221
fn warning_count(&self) -> usize {
193222
self.file_error_map
223+
.borrow()
194224
.iter()
195225
.map(|(_, errors)| errors.len())
196226
.sum()
@@ -204,7 +234,7 @@ impl FormatReport {
204234
&self,
205235
mut t: Box<term::Terminal<Output = io::Stderr>>,
206236
) -> Result<(), term::Error> {
207-
for (file, errors) in &self.file_error_map {
237+
for (file, errors) in &*self.file_error_map.borrow() {
208238
for error in errors {
209239
let prefix_space_len = error.line.to_string().len();
210240
let prefix_spaces = " ".repeat(1 + prefix_space_len);
@@ -250,7 +280,7 @@ impl FormatReport {
250280
}
251281
}
252282

253-
if !self.file_error_map.is_empty() {
283+
if !self.file_error_map.borrow().is_empty() {
254284
t.attr(term::Attr::Bold)?;
255285
write!(t, "warning: ")?;
256286
t.reset()?;
@@ -274,7 +304,7 @@ fn target_str(space_len: usize, target_len: usize) -> String {
274304
impl fmt::Display for FormatReport {
275305
// Prints all the formatting errors.
276306
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
277-
for (file, errors) in &self.file_error_map {
307+
for (file, errors) in &*self.file_error_map.borrow() {
278308
for error in errors {
279309
let prefix_space_len = error.line.to_string().len();
280310
let prefix_spaces = " ".repeat(1 + prefix_space_len);
@@ -313,7 +343,7 @@ impl fmt::Display for FormatReport {
313343
)?;
314344
}
315345
}
316-
if !self.file_error_map.is_empty() {
346+
if !self.file_error_map.borrow().is_empty() {
317347
writeln!(
318348
fmt,
319349
"warning: rustfmt may have failed to format. See previous {} errors.",
@@ -339,10 +369,11 @@ fn format_ast<F>(
339369
parse_session: &mut ParseSess,
340370
main_file: &FileName,
341371
config: &Config,
372+
report: FormatReport,
342373
mut after_file: F,
343374
) -> Result<(FileMap, bool), io::Error>
344375
where
345-
F: FnMut(&FileName, &mut String, &[(usize, usize)]) -> Result<bool, io::Error>,
376+
F: FnMut(&FileName, &mut String, &[(usize, usize)], &FormatReport) -> Result<bool, io::Error>,
346377
{
347378
let mut result = FileMap::new();
348379
// diff mode: check if any files are differing
@@ -360,7 +391,8 @@ where
360391
.file;
361392
let big_snippet = filemap.src.as_ref().unwrap();
362393
let snippet_provider = SnippetProvider::new(filemap.start_pos, big_snippet);
363-
let mut visitor = FmtVisitor::from_codemap(parse_session, config, &snippet_provider);
394+
let mut visitor =
395+
FmtVisitor::from_codemap(parse_session, config, &snippet_provider, report.clone());
364396
// Format inner attributes if available.
365397
if !krate.attrs.is_empty() && path == *main_file {
366398
visitor.skip_empty_lines(filemap.end_pos);
@@ -380,8 +412,7 @@ where
380412
::utils::count_newlines(&visitor.buffer)
381413
);
382414

383-
let filename = path.clone();
384-
has_diff |= match after_file(&filename, &mut visitor.buffer, &visitor.skipped_range) {
415+
has_diff |= match after_file(&path, &mut visitor.buffer, &visitor.skipped_range, &report) {
385416
Ok(result) => result,
386417
Err(e) => {
387418
// Create a new error with path_str to help users see which files failed
@@ -390,13 +421,13 @@ where
390421
}
391422
};
392423

393-
result.push((filename, visitor.buffer));
424+
result.push((path.clone(), visitor.buffer));
394425
}
395426

396427
Ok((result, has_diff))
397428
}
398429

399-
/// Returns true if the line with the given line number was skipped by `#[rustfmt_skip]`.
430+
/// Returns true if the line with the given line number was skipped by `#[rustfmt::skip]`.
400431
fn is_skipped_line(line_number: usize, skipped_range: &[(usize, usize)]) -> bool {
401432
skipped_range
402433
.iter()
@@ -429,7 +460,7 @@ fn format_lines(
429460
name: &FileName,
430461
skipped_range: &[(usize, usize)],
431462
config: &Config,
432-
report: &mut FormatReport,
463+
report: &FormatReport,
433464
) {
434465
let mut trims = vec![];
435466
let mut last_wspace: Option<usize> = None;
@@ -543,7 +574,7 @@ fn format_lines(
543574
}
544575
}
545576

546-
report.file_error_map.insert(name.clone(), errors);
577+
report.append(name.clone(), errors);
547578
}
548579

549580
fn parse_input<'sess>(
@@ -760,19 +791,20 @@ fn format_input_inner<T: Write>(
760791
));
761792
parse_session.span_diagnostic = Handler::with_emitter(true, false, silent_emitter);
762793

763-
let mut report = FormatReport::new();
794+
let report = FormatReport::new();
764795

765796
let format_result = format_ast(
766797
&krate,
767798
&mut parse_session,
768799
&main_file,
769800
config,
770-
|file_name, file, skipped_range| {
801+
report.clone(),
802+
|file_name, file, skipped_range, report| {
771803
// For some reason, the codemap does not include terminating
772804
// newlines so we must add one on for each file. This is sad.
773805
filemap::append_newline(file);
774806

775-
format_lines(file, file_name, skipped_range, config, &mut report);
807+
format_lines(file, file_name, skipped_range, config, report);
776808

777809
if let Some(ref mut out) = out {
778810
return filemap::write_file(file, file_name, out, config);
@@ -975,7 +1007,7 @@ mod unit_tests {
9751007

9761008
#[test]
9771009
fn test_format_code_block_fail() {
978-
#[rustfmt_skip]
1010+
#[rustfmt::skip]
9791011
let code_block = "this_line_is_100_characters_long_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx(x, y, z);";
9801012
assert!(format_code_block(code_block, &Config::default()).is_none());
9811013
}

src/rewrite.rs

+2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use syntax::parse::ParseSess;
1616
use config::{Config, IndentStyle};
1717
use shape::Shape;
1818
use visitor::SnippetProvider;
19+
use FormatReport;
1920

2021
use std::cell::RefCell;
2122

@@ -38,6 +39,7 @@ pub struct RewriteContext<'a> {
3839
// When rewriting chain, veto going multi line except the last element
3940
pub force_one_line_chain: RefCell<bool>,
4041
pub snippet_provider: &'a SnippetProvider<'a>,
42+
pub report: FormatReport,
4143
}
4244

4345
impl<'a> RewriteContext<'a> {

0 commit comments

Comments
 (0)