1 mod diagnostic;
2 mod diagnostic_builder;
3 mod error;
4 mod subdiagnostic;
5 mod utils;
6
7 use diagnostic::{DiagnosticDerive, LintDiagnosticDerive};
8 use proc_macro2::TokenStream;
9 use quote::format_ident;
10 use subdiagnostic::SubdiagnosticDeriveBuilder;
11 use synstructure::Structure;
12
13 /// Implements `#[derive(Diagnostic)]`, which allows for errors to be specified as a struct,
14 /// independent from the actual diagnostics emitting code.
15 ///
16 /// ```ignore (rust)
17 /// # extern crate rustc_errors;
18 /// # use rustc_errors::Applicability;
19 /// # extern crate rustc_span;
20 /// # use rustc_span::{symbol::Ident, Span};
21 /// # extern crate rust_middle;
22 /// # use rustc_middle::ty::Ty;
23 /// #[derive(Diagnostic)]
24 /// #[diag(borrowck_move_out_of_borrow, code = "E0505")]
25 /// pub struct MoveOutOfBorrowError<'tcx> {
26 /// pub name: Ident,
27 /// pub ty: Ty<'tcx>,
28 /// #[primary_span]
29 /// #[label]
30 /// pub span: Span,
31 /// #[label(first_borrow_label)]
32 /// pub first_borrow_span: Span,
33 /// #[suggestion(code = "{name}.clone()")]
34 /// pub clone_sugg: Option<(Span, Applicability)>
35 /// }
36 /// ```
37 ///
38 /// ```fluent
39 /// move_out_of_borrow = cannot move out of {$name} because it is borrowed
40 /// .label = cannot move out of borrow
41 /// .first_borrow_label = `{$ty}` first borrowed here
42 /// .suggestion = consider cloning here
43 /// ```
44 ///
45 /// Then, later, to emit the error:
46 ///
47 /// ```ignore (rust)
48 /// sess.emit_err(MoveOutOfBorrowError {
49 /// expected,
50 /// actual,
51 /// span,
52 /// first_borrow_span,
53 /// clone_sugg: Some(suggestion, Applicability::MachineApplicable),
54 /// });
55 /// ```
56 ///
57 /// See rustc dev guide for more examples on using the `#[derive(Diagnostic)]`:
58 /// <https://rustc-dev-guide.rust-lang.org/diagnostics/diagnostic-structs.html>
session_diagnostic_derive(s: Structure<'_>) -> TokenStream59 pub fn session_diagnostic_derive(s: Structure<'_>) -> TokenStream {
60 DiagnosticDerive::new(format_ident!("diag"), format_ident!("handler"), s).into_tokens()
61 }
62
63 /// Implements `#[derive(LintDiagnostic)]`, which allows for lints to be specified as a struct,
64 /// independent from the actual lint emitting code.
65 ///
66 /// ```ignore (rust)
67 /// #[derive(LintDiagnostic)]
68 /// #[diag(lint_atomic_ordering_invalid_fail_success)]
69 /// pub struct AtomicOrderingInvalidLint {
70 /// method: Symbol,
71 /// success_ordering: Symbol,
72 /// fail_ordering: Symbol,
73 /// #[label(fail_label)]
74 /// fail_order_arg_span: Span,
75 /// #[label(success_label)]
76 /// #[suggestion(
77 /// code = "std::sync::atomic::Ordering::{success_suggestion}",
78 /// applicability = "maybe-incorrect"
79 /// )]
80 /// success_order_arg_span: Span,
81 /// }
82 /// ```
83 ///
84 /// ```fluent
85 /// lint_atomic_ordering_invalid_fail_success = `{$method}`'s success ordering must be at least as strong as its failure ordering
86 /// .fail_label = `{$fail_ordering}` failure ordering
87 /// .success_label = `{$success_ordering}` success ordering
88 /// .suggestion = consider using `{$success_suggestion}` success ordering instead
89 /// ```
90 ///
91 /// Then, later, to emit the error:
92 ///
93 /// ```ignore (rust)
94 /// cx.struct_span_lint(INVALID_ATOMIC_ORDERING, fail_order_arg_span, AtomicOrderingInvalidLint {
95 /// method,
96 /// success_ordering,
97 /// fail_ordering,
98 /// fail_order_arg_span,
99 /// success_order_arg_span,
100 /// });
101 /// ```
102 ///
103 /// See rustc dev guide for more examples on using the `#[derive(LintDiagnostic)]`:
104 /// <https://rustc-dev-guide.rust-lang.org/diagnostics/diagnostic-structs.html#reference>
lint_diagnostic_derive(s: Structure<'_>) -> TokenStream105 pub fn lint_diagnostic_derive(s: Structure<'_>) -> TokenStream {
106 LintDiagnosticDerive::new(format_ident!("diag"), s).into_tokens()
107 }
108
109 /// Implements `#[derive(Subdiagnostic)]`, which allows for labels, notes, helps and
110 /// suggestions to be specified as a structs or enums, independent from the actual diagnostics
111 /// emitting code or diagnostic derives.
112 ///
113 /// ```ignore (rust)
114 /// #[derive(Subdiagnostic)]
115 /// pub enum ExpectedIdentifierLabel<'tcx> {
116 /// #[label(expected_identifier)]
117 /// WithoutFound {
118 /// #[primary_span]
119 /// span: Span,
120 /// }
121 /// #[label(expected_identifier_found)]
122 /// WithFound {
123 /// #[primary_span]
124 /// span: Span,
125 /// found: String,
126 /// }
127 /// }
128 ///
129 /// #[derive(Subdiagnostic)]
130 /// #[suggestion(style = "verbose",parser::raw_identifier)]
131 /// pub struct RawIdentifierSuggestion<'tcx> {
132 /// #[primary_span]
133 /// span: Span,
134 /// #[applicability]
135 /// applicability: Applicability,
136 /// ident: Ident,
137 /// }
138 /// ```
139 ///
140 /// ```fluent
141 /// parser_expected_identifier = expected identifier
142 ///
143 /// parser_expected_identifier_found = expected identifier, found {$found}
144 ///
145 /// parser_raw_identifier = escape `{$ident}` to use it as an identifier
146 /// ```
147 ///
148 /// Then, later, to add the subdiagnostic:
149 ///
150 /// ```ignore (rust)
151 /// diag.subdiagnostic(ExpectedIdentifierLabel::WithoutFound { span });
152 ///
153 /// diag.subdiagnostic(RawIdentifierSuggestion { span, applicability, ident });
154 /// ```
session_subdiagnostic_derive(s: Structure<'_>) -> TokenStream155 pub fn session_subdiagnostic_derive(s: Structure<'_>) -> TokenStream {
156 SubdiagnosticDeriveBuilder::new().into_tokens(s)
157 }
158