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.
This commit is contained in:
parent
67a59f6ee3
commit
d4ffd1efa4
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
7
src/formatting/generated.rs
Normal file
7
src/formatting/generated.rs
Normal file
@ -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"))
|
||||
}
|
@ -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();
|
||||
|
||||
|
@ -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| {
|
||||
(
|
||||
|
8
tests/source/configs/format_generated_files/false.rs
Normal file
8
tests/source/configs/format_generated_files/false.rs
Normal file
@ -0,0 +1,8 @@
|
||||
// @generated
|
||||
// rustfmt-format_generated_files: false
|
||||
|
||||
fn main()
|
||||
{
|
||||
println!("hello, world")
|
||||
;
|
||||
}
|
8
tests/source/configs/format_generated_files/true.rs
Normal file
8
tests/source/configs/format_generated_files/true.rs
Normal file
@ -0,0 +1,8 @@
|
||||
// @generated
|
||||
// rustfmt-format_generated_files: true
|
||||
|
||||
fn main()
|
||||
{
|
||||
println!("hello, world")
|
||||
;
|
||||
}
|
8
tests/target/configs/format_generated_files/false.rs
Normal file
8
tests/target/configs/format_generated_files/false.rs
Normal file
@ -0,0 +1,8 @@
|
||||
// @generated
|
||||
// rustfmt-format_generated_files: false
|
||||
|
||||
fn main()
|
||||
{
|
||||
println!("hello, world")
|
||||
;
|
||||
}
|
6
tests/target/configs/format_generated_files/true.rs
Normal file
6
tests/target/configs/format_generated_files/true.rs
Normal file
@ -0,0 +1,6 @@
|
||||
// @generated
|
||||
// rustfmt-format_generated_files: true
|
||||
|
||||
fn main() {
|
||||
println!("hello, world");
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user