@@ -5,7 +5,7 @@ use std::fmt::Debug;
5
5
6
6
use crate :: {
7
7
ast:: { ExprId , FieldId , ItemId , Span , StmtId , VariantId } ,
8
- context:: AstContext ,
8
+ context:: { with_cx , AstContext } ,
9
9
ffi:: { FfiSlice , FfiStr } ,
10
10
lint:: Lint ,
11
11
} ;
@@ -17,19 +17,34 @@ pub struct DiagnosticBuilder<'ast> {
17
17
lint : & ' static Lint ,
18
18
node : EmissionNodeId ,
19
19
msg : String ,
20
- span : Span < ' ast > ,
20
+ span : Option < Span < ' ast > > ,
21
21
parts : Vec < DiagnosticPart < String , Span < ' ast > > > ,
22
+ /// This flag indicates, if the diagnostic messages should actually be emitted
23
+ /// at the end. This might be false, if the lint is allowed at the emission location.
24
+ emit_lint : bool ,
22
25
}
23
26
24
27
#[ allow( clippy:: needless_pass_by_value) ] // `&impl ToString` doesn't work
25
28
impl < ' ast > DiagnosticBuilder < ' ast > {
29
+ pub ( crate ) fn new_dummy ( lint : & ' static Lint , node : EmissionNodeId ) -> Self {
30
+ Self {
31
+ lint,
32
+ node,
33
+ msg : String :: new ( ) ,
34
+ span : None ,
35
+ parts : vec ! [ ] ,
36
+ emit_lint : false ,
37
+ }
38
+ }
39
+
26
40
pub ( crate ) fn new ( lint : & ' static Lint , node : EmissionNodeId , msg : String , span : Span < ' ast > ) -> Self {
27
41
Self {
28
42
lint,
29
43
msg,
30
44
node,
31
- span,
45
+ span : Some ( span ) ,
32
46
parts : vec ! [ ] ,
47
+ emit_lint : true ,
33
48
}
34
49
}
35
50
@@ -45,7 +60,9 @@ impl<'ast> DiagnosticBuilder<'ast> {
45
60
/// |
46
61
/// ```
47
62
pub fn set_main_message ( & mut self , msg : impl ToString ) -> & mut Self {
48
- self . msg = msg. to_string ( ) ;
63
+ if self . emit_lint {
64
+ self . msg = msg. to_string ( ) ;
65
+ }
49
66
self
50
67
}
51
68
@@ -63,7 +80,10 @@ impl<'ast> DiagnosticBuilder<'ast> {
63
80
/// |
64
81
/// ```
65
82
pub fn set_main_span ( & mut self , span : & Span < ' ast > ) -> & mut Self {
66
- self . span = span. clone ( ) ;
83
+ if self . emit_lint {
84
+ self . span = Some ( span. clone ( ) ) ;
85
+ }
86
+
67
87
self
68
88
}
69
89
@@ -82,8 +102,12 @@ impl<'ast> DiagnosticBuilder<'ast> {
82
102
/// ```
83
103
///
84
104
/// [`Self::span_note`] can be used to highlight a relevant [`Span`].
85
- pub fn note ( & mut self , msg : impl ToString ) {
86
- self . parts . push ( DiagnosticPart :: Note { msg : msg. to_string ( ) } ) ;
105
+ pub fn note ( & mut self , msg : impl ToString ) -> & mut Self {
106
+ if self . emit_lint {
107
+ self . parts . push ( DiagnosticPart :: Note { msg : msg. to_string ( ) } ) ;
108
+ }
109
+
110
+ self
87
111
}
88
112
89
113
/// This function adds a note with a [`Span`] to the diagnostic message.
@@ -106,11 +130,15 @@ impl<'ast> DiagnosticBuilder<'ast> {
106
130
/// ```
107
131
///
108
132
/// [`Self::note`] can be used to add text notes without a span.
109
- pub fn span_note ( & mut self , msg : impl ToString , span : & Span < ' ast > ) {
110
- self . parts . push ( DiagnosticPart :: NoteSpan {
111
- msg : msg. to_string ( ) ,
112
- span : span. clone ( ) ,
113
- } ) ;
133
+ pub fn span_note ( & mut self , msg : impl ToString , span : & Span < ' ast > ) -> & mut Self {
134
+ if self . emit_lint {
135
+ self . parts . push ( DiagnosticPart :: NoteSpan {
136
+ msg : msg. to_string ( ) ,
137
+ span : span. clone ( ) ,
138
+ } ) ;
139
+ }
140
+
141
+ self
114
142
}
115
143
116
144
/// This function adds a help message. Help messages are intended to provide
@@ -130,7 +158,10 @@ impl<'ast> DiagnosticBuilder<'ast> {
130
158
/// [`Self::span_help`] can be used to highlight a relevant [`Span`].
131
159
/// [`Self::span_suggestion`] can be used to add a help message with a suggestion.
132
160
pub fn help ( & mut self , msg : impl ToString ) -> & mut Self {
133
- self . parts . push ( DiagnosticPart :: Help { msg : msg. to_string ( ) } ) ;
161
+ if self . emit_lint {
162
+ self . parts . push ( DiagnosticPart :: Help { msg : msg. to_string ( ) } ) ;
163
+ }
164
+
134
165
self
135
166
}
136
167
@@ -155,11 +186,15 @@ impl<'ast> DiagnosticBuilder<'ast> {
155
186
///
156
187
/// [`Self::help`] can be used to add a text help message without a [`Span`].
157
188
/// [`Self::span_suggestion`] can be used to add a help message with a suggestion.
158
- pub fn span_help ( & mut self , msg : impl ToString , span : & Span < ' ast > ) {
159
- self . parts . push ( DiagnosticPart :: HelpSpan {
160
- msg : msg. to_string ( ) ,
161
- span : span. clone ( ) ,
162
- } ) ;
189
+ pub fn span_help ( & mut self , msg : impl ToString , span : & Span < ' ast > ) -> & mut Self {
190
+ if self . emit_lint {
191
+ self . parts . push ( DiagnosticPart :: HelpSpan {
192
+ msg : msg. to_string ( ) ,
193
+ span : span. clone ( ) ,
194
+ } ) ;
195
+ }
196
+
197
+ self
163
198
}
164
199
165
200
/// This function adds a spanned help message with a suggestion. The suggestion
@@ -184,25 +219,70 @@ impl<'ast> DiagnosticBuilder<'ast> {
184
219
span : & Span < ' ast > ,
185
220
suggestion : impl ToString ,
186
221
app : Applicability ,
187
- ) {
188
- self . parts . push ( DiagnosticPart :: Suggestion {
189
- msg : msg. to_string ( ) ,
190
- span : span. clone ( ) ,
191
- sugg : suggestion. to_string ( ) ,
192
- app,
193
- } ) ;
222
+ ) -> & mut Self {
223
+ if self . emit_lint {
224
+ self . parts . push ( DiagnosticPart :: Suggestion {
225
+ msg : msg. to_string ( ) ,
226
+ span : span. clone ( ) ,
227
+ sugg : suggestion. to_string ( ) ,
228
+ app,
229
+ } ) ;
230
+ }
231
+ self
232
+ }
233
+
234
+ /// This function takes a closure, that is only executed, if the created
235
+ /// diagnostic is actually emitted in the end. This is useful for crafting
236
+ /// suggestions. Having them in a conditional closure will speedup the
237
+ /// linting process if the lint is allowed at a given location.
238
+ ///
239
+ /// ```
240
+ /// # use marker_api::prelude::*;
241
+ /// # marker_api::declare_lint!(
242
+ /// # /// Dummy
243
+ /// # LINT,
244
+ /// # Warn,
245
+ /// # );
246
+ /// # fn value_provider<'ast>(cx: &AstContext<'ast>, node: ExprKind<'ast>) {
247
+ /// cx.emit_lint(LINT, node, "<lint message>").decorate(|diag| {
248
+ /// // This closure is only called, if the lint is enabled. Here you
249
+ /// // can create a beautiful help message.
250
+ /// diag.help("<text>");
251
+ /// });
252
+ /// # }
253
+ /// ```
254
+ pub fn decorate < F > ( & mut self , decorate : F ) -> & mut Self
255
+ where
256
+ F : FnOnce ( & mut DiagnosticBuilder < ' ast > ) ,
257
+ {
258
+ if self . emit_lint {
259
+ decorate ( self ) ;
260
+ }
261
+ self
194
262
}
195
263
196
264
pub ( crate ) fn emit < ' builder > ( & ' builder self , cx : & AstContext < ' ast > ) {
197
- let parts: Vec < _ > = self . parts . iter ( ) . map ( DiagnosticPart :: to_ffi_part) . collect ( ) ;
198
- let diag = Diagnostic {
199
- lint : self . lint ,
200
- msg : self . msg . as_str ( ) . into ( ) ,
201
- node : self . node ,
202
- span : & self . span ,
203
- parts : parts. as_slice ( ) . into ( ) ,
204
- } ;
205
- cx. emit_diagnostic ( & diag) ;
265
+ if self . emit_lint {
266
+ let parts: Vec < _ > = self . parts . iter ( ) . map ( DiagnosticPart :: to_ffi_part) . collect ( ) ;
267
+ let span = self
268
+ . span
269
+ . as_ref ( )
270
+ . expect ( "always Some, if `DiagnosticBuilder::emit_lint` is true" ) ;
271
+ let diag = Diagnostic {
272
+ lint : self . lint ,
273
+ msg : self . msg . as_str ( ) . into ( ) ,
274
+ node : self . node ,
275
+ span,
276
+ parts : parts. as_slice ( ) . into ( ) ,
277
+ } ;
278
+ cx. emit_diagnostic ( & diag) ;
279
+ }
280
+ }
281
+ }
282
+
283
+ impl < ' ast > Drop for DiagnosticBuilder < ' ast > {
284
+ fn drop ( & mut self ) {
285
+ with_cx ( self , |cx| self . emit ( cx) ) ;
206
286
}
207
287
}
208
288
0 commit comments