diff --git a/src/diag.md b/src/diag.md index 6679e424..a2ec3bb7 100644 --- a/src/diag.md +++ b/src/diag.md @@ -22,12 +22,13 @@ reporting errors. [errors]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/index.html -Most "session"-like types in the compiler (e.g. [`Session`][session]) have +[`Session`][session] and [`ParseSess`][parsesses] have methods (or fields with methods) that allow reporting errors. These methods usually have names like `span_err` or `struct_span_err` or `span_warn`, etc... There are lots of them; they emit different types of "errors", such as warnings, errors, fatal errors, suggestions, etc. +[parsesses]: https://doc.rust-lang.org/nightly/nightly-rustc/syntax/parse/struct.ParseSess.html [session]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc/session/struct.Session.html In general, there are two class of such methods: ones that emit an error @@ -45,20 +46,64 @@ before emitting it by calling the [`emit`][emit] method. See the [diagbuild]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/diagnostic_builder/struct.DiagnosticBuilder.html [emit]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/diagnostic_builder/struct.DiagnosticBuilder.html#method.emit -For example, to add a help message to an error, one might do: +```rust,ignore +// Get a DiagnosticBuilder. This does _not_ emit an error yet. +let mut err = sess.struct_span_err(sp, "oh no! this is an error!"); + +// In some cases, you might need to check if `sp` is generated by a macro to +// avoid printing weird errors about macro-generated code. + +if let Some(snippet) = sess.codemap().span_to_snippet(sp) { + // Use the snippet to generate a suggested fix + err.span_suggestion(suggestion_sp, "try using a qux here", format!("qux {}", snip)); +} else { + // If we weren't able to generate a snippet, then emit a "help" message + // instead of a concrete "suggestion". In practice this is unlikely to be + // reached. + err.span_help(suggestion_sp, "you could use a qux here instead"); +} + +// emit the error +err.emit(); +``` + +## Suggestions + +We would like to make edition transitions as smooth as possible. To that end, +`rustfix` can use compiler suggestions to automatically fix code. For example, +we could use `rustfix` to mechanically apply the `qux` suggestion from the +previous example. However, not all suggestions are mechanically applicable. We +use the [`span_suggestion_with_applicability`][sswa] method of +`DiagnosticBuilder` to inform the emitter of whether a suggestion is +mechanically applicable or not. This information, in turn, is outputed by +rustc when the error format is `json`, which is used by `rustfix`. + +[sswa]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/struct.DiagnosticBuilder.html#method.span_suggestion_with_applicability + +For example, to make our `qux` suggestion machine-applicable, we would do: ```rust,ignore -let snip = sess.codemap().span_to_snippet(sp); +let mut err = sess.struct_span_err(sp, "oh no! this is an error!"); -sess.struct_span_err(sp, "oh no! this is an error!") - .span_suggestion(other_sp, "try using a qux here", format!("qux {}", snip)) - .emit(); +if let Some(snippet) = sess.codemap().span_to_snippet(sp) { + // Add applicability info! + err.span_suggestion_with_applicability( + suggestion_sp, + "try using a qux here", + format!("qux {}", snip), + Applicability::MachineApplicable, + ); +} else { + err.span_help(suggestion_sp, "you could use a qux here instead"); +} + +err.emit(); ``` This might emit an error like ```console -$ rustc mycode.rs +$ rustc mycode.rs error[E0999]: oh no! this is an error! --> mycode.rs:3:5 | @@ -70,10 +115,29 @@ error: aborting due to previous error For more information about this error, try `rustc --explain E0999`. ``` +In some cases, like when the suggestion spans multiple lines or when there are +multiple suggestions, the suggestions are displayed on their own: + +```console +error[E0999]: oh no! this is an error! + --> mycode.rs:3:5 + | +3 | sad() + | ^ +help: try using a qux here: + | +3 | qux sad() + | ^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0999`. +``` + ## Lints The compiler linting infrastructure is defined in the [`rustc::lint`][rlint] -module. +module. [rlint]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc/lint/index.html @@ -138,7 +202,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for WhileTrue { } ``` -### Edition Lints +### Edition-gated Lints Sometimes we want to change the behavior of a lint in a new edition. To do this, we just add the transition to our invocation of `declare_lint!`: @@ -155,6 +219,10 @@ declare_lint! { This makes the `ANONYMOUS_PARAMETERS` lint allow-by-default in the 2015 edition but warn-by-default in the 2018 edition. +Lints that represent an incompatibility (i.e. error) in the upcoming edition should +also be registered as `FutureIncompatibilityLint`s in +[`register_builtins`][rbuiltins] function in [`rustc_lint::lib`][builtin]. + ### Lint Groups Lints can be turned on in groups. These groups are declared in the