Skip to content

Commit 2aacad8

Browse files
topecongirostepancheg
authored andcommitted
Support @generated marker to skip code formatting
This is a copy of rust-lang#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](stepancheg/rust-protobuf#493), [two](stepancheg/rust-protobuf#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.
1 parent 6495024 commit 2aacad8

File tree

10 files changed

+63
-2
lines changed

10 files changed

+63
-2
lines changed

Configurations.md

+9
Original file line numberDiff line numberDiff line change
@@ -924,6 +924,15 @@ fn add_one(x: i32) -> i32 {
924924
}
925925
```
926926

927+
## `format_generated_files`
928+
929+
Format generated files. A file is considered generated
930+
if any of the first five lines contains `@generated` marker.
931+
932+
- **Default value**: `false`
933+
- **Possible values**: `true`, `false`
934+
- **Stable**: No
935+
927936
## `format_macro_matchers`
928937

929938
Format the metavariable matching patterns in macros.

src/config/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ create_config! {
136136
inline_attribute_width: usize, 0, false,
137137
"Write an item and its attribute on the same line \
138138
if their combined width is below a threshold";
139+
format_generated_files: bool, false, false, "Format generated files";
139140

140141
// Options that can change the source code beyond whitespace/blocks (somewhat linty things)
141142
merge_derives: bool, true, true, "Merge multiple `#[derive(...)]` into a single one";
@@ -604,6 +605,7 @@ blank_lines_lower_bound = 0
604605
edition = "2015"
605606
version = "One"
606607
inline_attribute_width = 0
608+
format_generated_files = false
607609
merge_derives = true
608610
use_try_shorthand = false
609611
use_field_init_shorthand = false

src/formatting.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use rustc_span::Span;
1010
use self::newline_style::apply_newline_style;
1111
use crate::comment::{CharClasses, FullCodeCharKind};
1212
use crate::config::{Config, FileName, Verbosity};
13+
use crate::formatting::generated::is_generated_file;
1314
use crate::issues::BadIssueSeeker;
1415
use crate::modules::Module;
1516
use crate::syntux::parser::{DirectoryOwnership, Parser, ParserError};
@@ -18,6 +19,7 @@ use crate::utils::count_newlines;
1819
use crate::visitor::FmtVisitor;
1920
use crate::{modules, source_file, ErrorKind, FormatReport, Input, Session};
2021

22+
mod generated;
2123
mod newline_style;
2224

2325
// A map of the files of a crate, with their new content
@@ -103,7 +105,12 @@ fn format_project<T: FormatHandler>(
103105
context.parse_session.set_silent_emitter();
104106

105107
for (path, module) in files {
106-
let should_ignore = !input_is_stdin && context.ignore_file(&path);
108+
let source_file = context.parse_session.span_to_file_contents(module.span);
109+
let src = source_file.src.as_ref().expect("SourceFile without src");
110+
111+
let should_ignore = (!input_is_stdin && context.ignore_file(&path))
112+
|| (!config.format_generated_files() && is_generated_file(src));
113+
107114
if (config.skip_children() && path != main_file) || should_ignore {
108115
continue;
109116
}

src/formatting/generated.rs

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
/// Returns `true` if the given span is a part of generated files.
2+
pub(super) fn is_generated_file(original_snippet: &str) -> bool {
3+
original_snippet
4+
.lines()
5+
.take(5) // looking for marker only in the beginning of the file
6+
.any(|line| line.contains("@generated"))
7+
}

src/syntux/session.rs

+6
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,12 @@ impl ParseSess {
175175
self.parse_sess.source_map().span_to_filename(span).into()
176176
}
177177

178+
pub(crate) fn span_to_file_contents(&self, span: Span) -> Lrc<rustc_span::SourceFile> {
179+
self.parse_sess
180+
.source_map()
181+
.lookup_source_file(span.data().lo)
182+
}
183+
178184
pub(crate) fn span_to_first_line_string(&self, span: Span) -> String {
179185
let file_lines = self.parse_sess.source_map().span_to_lines(span).ok();
180186

src/test/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -693,7 +693,7 @@ fn read_significant_comments(file_name: &Path) -> HashMap<String, String> {
693693
reader
694694
.lines()
695695
.map(|line| line.expect("failed getting line"))
696-
.take_while(|line| line_regex.is_match(line))
696+
.filter(|line| line_regex.is_match(line))
697697
.filter_map(|line| {
698698
regex.captures_iter(&line).next().map(|capture| {
699699
(
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// @generated
2+
// rustfmt-format_generated_files: false
3+
4+
fn main()
5+
{
6+
println!("hello, world")
7+
;
8+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// @generated
2+
// rustfmt-format_generated_files: true
3+
4+
fn main()
5+
{
6+
println!("hello, world")
7+
;
8+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// @generated
2+
// rustfmt-format_generated_files: false
3+
4+
fn main()
5+
{
6+
println!("hello, world")
7+
;
8+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// @generated
2+
// rustfmt-format_generated_files: true
3+
4+
fn main() {
5+
println!("hello, world");
6+
}

0 commit comments

Comments
 (0)