macros: add diagnostic derive for lints
`SessionDiagnostic` isn't suitable for use on lints as whether or not it creates an error or a warning is decided at compile-time by the macro, whereas lints decide this at runtime based on the location of the lint being reported (as it will depend on the user's `allow`/`deny` attributes, etc). Re-using most of the machinery for `SessionDiagnostic`, this macro introduces a `LintDiagnostic` derive which implements a `DecorateLint` trait, taking a `LintDiagnosticBuilder` and adding to the lint according to the diagnostic struct.
This commit is contained in:
parent
7f9d8480d6
commit
9d864c8d56
12 changed files with 847 additions and 614 deletions
|
@ -1,10 +1,11 @@
|
|||
mod diagnostic;
|
||||
mod diagnostic_builder;
|
||||
mod error;
|
||||
mod fluent;
|
||||
mod subdiagnostic;
|
||||
mod utils;
|
||||
|
||||
use diagnostic::SessionDiagnosticDerive;
|
||||
use diagnostic::{LintDiagnosticDerive, SessionDiagnosticDerive};
|
||||
pub(crate) use fluent::fluent_messages;
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::format_ident;
|
||||
|
@ -58,11 +59,53 @@ use synstructure::Structure;
|
|||
/// See rustc dev guide for more examples on using the `#[derive(SessionDiagnostic)]`:
|
||||
/// <https://rustc-dev-guide.rust-lang.org/diagnostics/diagnostic-structs.html>
|
||||
pub fn session_diagnostic_derive(s: Structure<'_>) -> TokenStream {
|
||||
// Names for the diagnostic we build and the session we build it from.
|
||||
let diag = format_ident!("diag");
|
||||
let sess = format_ident!("sess");
|
||||
SessionDiagnosticDerive::new(format_ident!("diag"), format_ident!("sess"), s).into_tokens()
|
||||
}
|
||||
|
||||
SessionDiagnosticDerive::new(diag, sess, s).into_tokens()
|
||||
/// Implements `#[derive(LintDiagnostic)]`, which allows for lints to be specified as a struct,
|
||||
/// independent from the actual lint emitting code.
|
||||
///
|
||||
/// ```ignore (rust)
|
||||
/// #[derive(LintDiagnostic)]
|
||||
/// #[lint(lint::atomic_ordering_invalid_fail_success)]
|
||||
/// pub struct AtomicOrderingInvalidLint {
|
||||
/// method: Symbol,
|
||||
/// success_ordering: Symbol,
|
||||
/// fail_ordering: Symbol,
|
||||
/// #[label(lint::fail_label)]
|
||||
/// fail_order_arg_span: Span,
|
||||
/// #[label(lint::success_label)]
|
||||
/// #[suggestion(
|
||||
/// code = "std::sync::atomic::Ordering::{success_suggestion}",
|
||||
/// applicability = "maybe-incorrect"
|
||||
/// )]
|
||||
/// success_order_arg_span: Span,
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// ```fluent
|
||||
/// lint-atomic-ordering-invalid-fail-success = `{$method}`'s success ordering must be at least as strong as its failure ordering
|
||||
/// .fail-label = `{$fail_ordering}` failure ordering
|
||||
/// .success-label = `{$success_ordering}` success ordering
|
||||
/// .suggestion = consider using `{$success_suggestion}` success ordering instead
|
||||
/// ```
|
||||
///
|
||||
/// Then, later, to emit the error:
|
||||
///
|
||||
/// ```ignore (rust)
|
||||
/// cx.struct_span_lint(INVALID_ATOMIC_ORDERING, fail_order_arg_span, AtomicOrderingInvalidLint {
|
||||
/// method,
|
||||
/// success_ordering,
|
||||
/// fail_ordering,
|
||||
/// fail_order_arg_span,
|
||||
/// success_order_arg_span,
|
||||
/// });
|
||||
/// ```
|
||||
///
|
||||
/// See rustc dev guide for more examples on using the `#[derive(LintDiagnostic)]`:
|
||||
/// <https://rustc-dev-guide.rust-lang.org/diagnostics/sessiondiagnostic.html>
|
||||
pub fn lint_diagnostic_derive(s: Structure<'_>) -> TokenStream {
|
||||
LintDiagnosticDerive::new(format_ident!("diag"), s).into_tokens()
|
||||
}
|
||||
|
||||
/// Implements `#[derive(SessionSubdiagnostic)]`, which allows for labels, notes, helps and
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue