Skip to content

Commit

Permalink
Support @generated marker to skip code formatting
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
topecongiro authored and stepancheg committed Jun 22, 2021
1 parent 6495024 commit b1d0548
Show file tree
Hide file tree
Showing 10 changed files with 62 additions and 2 deletions.
8 changes: 8 additions & 0 deletions Configurations.md
Original file line number Diff line number Diff line change
Expand Up @@ -924,6 +924,14 @@ fn add_one(x: i32) -> i32 {
}
```

## `format_generated_files`

Format generated files. A file is considered as generated if the file starts with `// @generated`.

- **Default value**: `false`
- **Possible values**: `true`, `false`
- **Stable**: No

## `format_macro_matchers`

Format the metavariable matching patterns in macros.
Expand Down
2 changes: 2 additions & 0 deletions src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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
Expand Down
9 changes: 8 additions & 1 deletion src/formatting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand All @@ -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
Expand Down Expand Up @@ -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;
}
Expand Down
7 changes: 7 additions & 0 deletions src/formatting/generated.rs
Original file line number Diff line number Diff line change
@@ -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"))
}
6 changes: 6 additions & 0 deletions src/syntux/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down
2 changes: 1 addition & 1 deletion src/test/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -693,7 +693,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| {
(
Expand Down
8 changes: 8 additions & 0 deletions tests/source/configs/format_generated_files/false.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// @generated
// rustfmt-format_generated_files: false

fn main()
{
println!("hello, world")
;
}
8 changes: 8 additions & 0 deletions tests/source/configs/format_generated_files/true.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// @generated
// rustfmt-format_generated_files: true

fn main()
{
println!("hello, world")
;
}
8 changes: 8 additions & 0 deletions tests/target/configs/format_generated_files/false.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// @generated
// rustfmt-format_generated_files: false

fn main()
{
println!("hello, world")
;
}
6 changes: 6 additions & 0 deletions tests/target/configs/format_generated_files/true.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// @generated
// rustfmt-format_generated_files: true

fn main() {
println!("hello, world");
}

0 comments on commit b1d0548

Please sign in to comment.