diff options
| author | Seiichi Uchida <seuchida@gmail.com> | 2020-07-10 11:23:12 +0900 |
|---|---|---|
| committer | Caleb Cartwright <calebcartwright@users.noreply.github.com> | 2021-09-14 21:22:26 -0500 |
| commit | d4ffd1efa4c83084f05f6e83585ae0a70450bcfd (patch) | |
| tree | d44f5cb3e989ba0a9eb6c1fef730ec807fac96f3 | |
| parent | 67a59f6ee35c3cfd75e2aab5a8475608e167840b (diff) | |
| download | rust-d4ffd1efa4c83084f05f6e83585ae0a70450bcfd.tar.gz rust-d4ffd1efa4c83084f05f6e83585ae0a70450bcfd.zip | |
Support @generated marker to skip code formatting
This is a copy of #4296 with these changes: * file is not reopened again to find if the file is generated * first five lines are scanned for `@generated` marker instead of one * no attempt is made to only search for marker in comments `@generated` marker is used by certain tools to understand that the file is generated, so it should be treated differently than a file written by a human: * linters should not be invoked on these files, * diffs in these files are less important, * and these files should not be reformatted. This PR proposes builtin support for `@generated` marker. I have not found a standard for a generated file marker, but: * Facebook [uses `@generated` marker](https://tinyurl.com/fb-generated) * Phabricator tool which was spawned from Facebook internal tool [also understands `@generated` marker](https://git.io/JnVHa) * Cargo inserts `@generated` marker into [generated Cargo.lock files](https://git.io/JnVHP) My personal story is that rust-protobuf project which I maintain was broken twice because of incompatibilities/bugs in rustfmt marker handling: [one](https://github.com/stepancheg/rust-protobuf/issues/493), [two](https://github.com/stepancheg/rust-protobuf/issues/551). (Also, rust-protobuf started generating `@generated` marker [6 years ago](https://git.io/JnV5h)). While rustfmt AST markers are useful to apply to a certain AST elements, disable whole-file-at-once all-tools-at-once text level marker might be easier to use and more reliable for generated code.
| -rw-r--r-- | Configurations.md | 9 | ||||
| -rw-r--r-- | src/config/mod.rs | 2 | ||||
| -rw-r--r-- | src/formatting.rs | 9 | ||||
| -rw-r--r-- | src/formatting/generated.rs | 7 | ||||
| -rw-r--r-- | src/syntux/session.rs | 6 | ||||
| -rw-r--r-- | src/test/mod.rs | 2 | ||||
| -rw-r--r-- | tests/source/configs/format_generated_files/false.rs | 8 | ||||
| -rw-r--r-- | tests/source/configs/format_generated_files/true.rs | 8 | ||||
| -rw-r--r-- | tests/target/configs/format_generated_files/false.rs | 8 | ||||
| -rw-r--r-- | tests/target/configs/format_generated_files/true.rs | 6 |
10 files changed, 63 insertions, 2 deletions
diff --git a/Configurations.md b/Configurations.md index 469deccc56e..84e8c3f7db6 100644 --- a/Configurations.md +++ b/Configurations.md @@ -924,6 +924,15 @@ fn add_one(x: i32) -> i32 { } ``` +## `format_generated_files` + +Format generated files. A file is considered generated +if any of the first five lines contains `@generated` marker. + +- **Default value**: `false` +- **Possible values**: `true`, `false` +- **Stable**: No + ## `format_macro_matchers` Format the metavariable matching patterns in macros. diff --git a/src/config/mod.rs b/src/config/mod.rs index 8c04363b1fd..3d6e32fdb60 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -136,6 +136,7 @@ create_config! { inline_attribute_width: usize, 0, false, "Write an item and its attribute on the same line \ if their combined width is below a threshold"; + format_generated_files: bool, false, false, "Format generated files"; // Options that can change the source code beyond whitespace/blocks (somewhat linty things) merge_derives: bool, true, true, "Merge multiple `#[derive(...)]` into a single one"; @@ -604,6 +605,7 @@ blank_lines_lower_bound = 0 edition = "2015" version = "One" inline_attribute_width = 0 +format_generated_files = false merge_derives = true use_try_shorthand = false use_field_init_shorthand = false diff --git a/src/formatting.rs b/src/formatting.rs index e0403574eeb..9ef47b887ca 100644 --- a/src/formatting.rs +++ b/src/formatting.rs @@ -10,6 +10,7 @@ use rustc_span::Span; use self::newline_style::apply_newline_style; use crate::comment::{CharClasses, FullCodeCharKind}; use crate::config::{Config, FileName, Verbosity}; +use crate::formatting::generated::is_generated_file; use crate::issues::BadIssueSeeker; use crate::modules::Module; use crate::syntux::parser::{DirectoryOwnership, Parser, ParserError}; @@ -18,6 +19,7 @@ use crate::utils::count_newlines; use crate::visitor::FmtVisitor; use crate::{modules, source_file, ErrorKind, FormatReport, Input, Session}; +mod generated; mod newline_style; // A map of the files of a crate, with their new content @@ -103,7 +105,12 @@ fn format_project<T: FormatHandler>( context.parse_session.set_silent_emitter(); for (path, module) in files { - let should_ignore = !input_is_stdin && context.ignore_file(&path); + let source_file = context.parse_session.span_to_file_contents(module.span); + let src = source_file.src.as_ref().expect("SourceFile without src"); + + let should_ignore = (!input_is_stdin && context.ignore_file(&path)) + || (!config.format_generated_files() && is_generated_file(src)); + if (config.skip_children() && path != main_file) || should_ignore { continue; } diff --git a/src/formatting/generated.rs b/src/formatting/generated.rs new file mode 100644 index 00000000000..58f43f17ee1 --- /dev/null +++ b/src/formatting/generated.rs @@ -0,0 +1,7 @@ +/// Returns `true` if the given span is a part of generated files. +pub(super) fn is_generated_file(original_snippet: &str) -> bool { + original_snippet + .lines() + .take(5) // looking for marker only in the beginning of the file + .any(|line| line.contains("@generated")) +} diff --git a/src/syntux/session.rs b/src/syntux/session.rs index 870f0acfe39..94257e1ce7f 100644 --- a/src/syntux/session.rs +++ b/src/syntux/session.rs @@ -175,6 +175,12 @@ impl ParseSess { self.parse_sess.source_map().span_to_filename(span).into() } + pub(crate) fn span_to_file_contents(&self, span: Span) -> Lrc<rustc_span::SourceFile> { + self.parse_sess + .source_map() + .lookup_source_file(span.data().lo) + } + pub(crate) fn span_to_first_line_string(&self, span: Span) -> String { let file_lines = self.parse_sess.source_map().span_to_lines(span).ok(); diff --git a/src/test/mod.rs b/src/test/mod.rs index cb52346a13a..ece1b91bfd7 100644 --- a/src/test/mod.rs +++ b/src/test/mod.rs @@ -694,7 +694,7 @@ fn read_significant_comments(file_name: &Path) -> HashMap<String, String> { reader .lines() .map(|line| line.expect("failed getting line")) - .take_while(|line| line_regex.is_match(line)) + .filter(|line| line_regex.is_match(line)) .filter_map(|line| { regex.captures_iter(&line).next().map(|capture| { ( diff --git a/tests/source/configs/format_generated_files/false.rs b/tests/source/configs/format_generated_files/false.rs new file mode 100644 index 00000000000..dec1e00d117 --- /dev/null +++ b/tests/source/configs/format_generated_files/false.rs @@ -0,0 +1,8 @@ +// @generated +// rustfmt-format_generated_files: false + +fn main() +{ + println!("hello, world") + ; +} diff --git a/tests/source/configs/format_generated_files/true.rs b/tests/source/configs/format_generated_files/true.rs new file mode 100644 index 00000000000..a25ddc25a6a --- /dev/null +++ b/tests/source/configs/format_generated_files/true.rs @@ -0,0 +1,8 @@ +// @generated +// rustfmt-format_generated_files: true + +fn main() +{ + println!("hello, world") + ; +} diff --git a/tests/target/configs/format_generated_files/false.rs b/tests/target/configs/format_generated_files/false.rs new file mode 100644 index 00000000000..dec1e00d117 --- /dev/null +++ b/tests/target/configs/format_generated_files/false.rs @@ -0,0 +1,8 @@ +// @generated +// rustfmt-format_generated_files: false + +fn main() +{ + println!("hello, world") + ; +} diff --git a/tests/target/configs/format_generated_files/true.rs b/tests/target/configs/format_generated_files/true.rs new file mode 100644 index 00000000000..5fea7e8b341 --- /dev/null +++ b/tests/target/configs/format_generated_files/true.rs @@ -0,0 +1,6 @@ +// @generated +// rustfmt-format_generated_files: true + +fn main() { + println!("hello, world"); +} |
