diff --git a/text/3850-autogenerated-attr.md b/text/3850-autogenerated-attr.md new file mode 100644 index 00000000000..75c28df9f57 --- /dev/null +++ b/text/3850-autogenerated-attr.md @@ -0,0 +1,121 @@ +- Feature Name: autogenerated_attr +- Start Date: 2025-08-24 +- RFC PR: [rust-lang/rfcs#3850](https://github.com/rust-lang/rfcs/pull/3850) +- Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/0000) + +# Summary +[summary]: #summary + +Add an attribute for marking items as being generated by a tool. +```rust +mod foo { + #![autogenerated( + by = "example tool", + suppress_lints = false, + format = true, + regen_hint = "./regen_example_tool", + document = false, + stable_api = true, + )] + // autogenerated code here... +} +``` +Many attributes could be provided to allow easy configuration of what would break code and what wouldn't. For example, if someone is using a test and string manipulation to change code at test time, then the tool likely would need `format = false`. + +# Motivation +[motivation]: #motivation + +Rust doesn't have a general attribute for this (some more specific attributes do exist, such as `#[automatically_derived]`), and this would be useful for scenarios such as: +- `rust-analyzer`: Mark files as autogenerated and discourage users from editing them +- `rustfmt`: Don't format files marked as autogenerated by default +- `clippy` and `rustc`: Suppress lints in autogenerated files by default - in other words, reset the list of lints to empty outside of lints marked explicitly in the file +- `clippy`: Add a `clippy::restriction` lint to not allow using autogenerated code. Also, add a lint to encourage providing the `by` and `regen_hint` parameters. +- `rustc`: Reduce error verbosity in autogenerated files and reference the tool that created the file, particularly for syntax errors +- `rustdoc`: Mark autogenerated files as such and state that the API may change over time +- Code line counters: Don't count lines of code in autogenerated files + +This is just a rough idea of what this RFC could enable, and not by any means an exhaustive list. + +# Guide-level explanation +[guide-level-explanation]: #guide-level-explanation + +When writing tools that produce Rust code, they should add a `#[autogenerated]` attribute to the generated code. This attribute can be added onto any item, such as modules, but also functions, constants, etc. The attribute takes many parameters: +```rust +#[autogenerated( + by = "example tool", // The tool that created this item - required + suppress_lints = false, // Whether to suppress lints on this code - default true + format = true, // Whether to format these items - default false + regen_hint = "./regen_example_tool", // A hint for how to regenerate the item - strongly encouraged to be provided + document = true, // Whether to document the items or not - default true + rustdoc_marker = false, // Whether to have a special marker stating that the item is autogenerated + stable_api = true, // Whether the item has a stable API and shouldn't trigger lints for accessing it or it's subitems - default false + discourage_editing = false, // Whether IDEs and rust-analyzer should discourage editing this item. Default true. +)] +``` + +These parameters are used to configure the behavior of different tools. Think of this feature as a way to communicate to many different tools at once how this autogenerated item should be treated. This can also be used to communicate to IDEs and `rust-analyzer` that this item should be marked as autogenerated and that it shouldn't be edited. + +# Reference-level explanation +[reference-level-explanation]: #reference-level-explanation + +This has no direct effect on how Rust is parsed. Instead, each tool will dictate how to understand the attribute based on what the tool is/does. Effects that commonly used tools would need to worry about were specified in the [motivation section](motivation). Most tools would need to worry about parsing the `by` attribute and whichever others affect the tool itself, and then use the `by` attribute for better error messages. For example, instead of: + +```plain +error: expected one of `(`, `[`, or `{`, found `` +--> foobar.rs:2:1 +| +2 | not rust +| ^ expected one of `(`, `[`, or `{` + +error: aborting due to 1 previous error +``` + +This message could be output: + +```plain +error: expected one of `(`, `[`, or `{`, found `` +--> foobar.rs:2:1 - generated by example tool (is there a bug in this tool?) +error: aborting due to 1 previous error +``` + +# Drawbacks +[drawbacks]: #drawbacks + +There aren't many drawbacks - if a tool doesn't understand the attribute then it should just skip over it. One problem that could arise is tools having their own parameters for the attribute that aren't specified, and it's unclear how to work around that. + +# Rationale and alternatives +[rationale-and-alternatives]: #rationale-and-alternatives + +Unlike many other languages with a similar feature, we have attributes which can be used for easy scoping like this. Other possible designs commonly used in other languages are a simple comment, such as Go's regex matching at the start of a file: +```regex +^// Code generated .* DO NOT EDIT.$ +``` +or C#'s: +```csharp +// +// (arbitrary text, usually a long description of the file) +// +``` +However, these both have the same problem: All that tools can do is check if a file is autogenerated, and nothing else. The design being suggested in this RFC allows tools to configure themselves to work better with autogenerated files and even see which tool made them. Another problem with this comment approach is it only supports files, not arbitrary items. + +This could in theory be done in a tool, however it works much better as a language feature for consistency's sake. Also, if it were done in a tool, where would it be placed? It wouldn't fit in any of the current ones given it's general and wouldn't be worth creating a new one for this. That's a bit of a nitpick however. + +This also improves code readability, allowing users and tools alike to easily see which tool created the generated code and even roughly how it was created (through `regen_hint`). + +Some things for individual tools do already exist such as `#[rustfmt::skip]`, however these of course apply only to individual tools meaning that a more general attribute would work well for this scenario. + +# Prior art +[prior-art]: #prior-art + +Similar features have been implemented in other languages, however usually as just a comment. Examples for Go and C# (the only languages with a standard for autogenerated files I could find) were shared in [the above section](rationale-and-alternatives). Rust also already has [`#[automatically_derived]`](https://doc.rust-lang.org/reference/attributes/derive.html#the-automatically_derived-attribute) for marking derived implementations along with some attributes for individual tools to configure them as mentioned before. + +# Unresolved questions +[unresolved-questions]: #unresolved-questions + +1. How could other tools configure themselves for the autogenerated attribute? I'd like to answer this either before the RFC is merged or before stabilization. One answer could be just stating it's out of scope. +2. What if you want some of these attributes without marking a file as autogenerated? This is out of scope. Many of them already exist (e.g. `#[rustfmt::skip]`) and the ones that don't probably shouldn't exist outside of autogenerated files (e.g. `suppress_lints`, `discourage_editing`) or wouldn't make sense outside of these files (e.g. `stable_api` (partially exists inversely with `#[nonexhaustive]`), `rustdoc_marker`). + +# Future possibilities +[future-possibilities]: #future-possibilities + +A natural extension that would answer question number one in [unresolved questions](unresolved-questions) is having some kind of standard of connecting certain proc macros to this attribute, but that'd be a much larger/more important RFC. Another thing would be adding more attributes to this for configuring future tools.