]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_lint/src/lints.rs
add: `emit{,_spanned}_lint` for `LintLevelsBuilder`
[rust.git] / compiler / rustc_lint / src / lints.rs
1 use rustc_errors::{fluent, AddToDiagnostic, Applicability, DecorateLint};
2 use rustc_hir::def_id::DefId;
3 use rustc_macros::{LintDiagnostic, Subdiagnostic};
4 use rustc_middle::ty::{Predicate, Ty, TyCtxt};
5 use rustc_span::{symbol::Ident, Span, Symbol};
6
7 use crate::LateContext;
8
9 // array_into_iter.rs
10 #[derive(LintDiagnostic)]
11 #[diag(lint_array_into_iter)]
12 pub struct ArrayIntoIterDiag<'a> {
13     pub target: &'a str,
14     #[suggestion(use_iter_suggestion, code = "iter", applicability = "machine-applicable")]
15     pub suggestion: Span,
16     #[subdiagnostic]
17     pub sub: Option<ArrayIntoIterDiagSub>,
18 }
19
20 #[derive(Subdiagnostic)]
21 pub enum ArrayIntoIterDiagSub {
22     #[suggestion(remove_into_iter_suggestion, code = "", applicability = "maybe-incorrect")]
23     RemoveIntoIter {
24         #[primary_span]
25         span: Span,
26     },
27     #[multipart_suggestion(use_explicit_into_iter_suggestion, applicability = "maybe-incorrect")]
28     UseExplicitIntoIter {
29         #[suggestion_part(code = "IntoIterator::into_iter(")]
30         start_span: Span,
31         #[suggestion_part(code = ")")]
32         end_span: Span,
33     },
34 }
35
36 // enum_intrinsics_non_enums.rs
37 #[derive(LintDiagnostic)]
38 #[diag(lint_enum_intrinsics_mem_discriminant)]
39 pub struct EnumIntrinsicsMemDiscriminate<'a> {
40     pub ty_param: Ty<'a>,
41     #[note]
42     pub note: Span,
43 }
44
45 #[derive(LintDiagnostic)]
46 #[diag(lint_enum_intrinsics_mem_variant)]
47 #[note]
48 pub struct EnumIntrinsicsMemVariant<'a> {
49     pub ty_param: Ty<'a>,
50 }
51
52 // levels.rs
53 #[derive(LintDiagnostic)]
54 #[diag(lint::deprecated_lint_name)]
55 pub struct DeprecatedLintName<'a> {
56     pub name: String,
57     #[suggestion(code = "{replace}", applicability = "machine-applicable")]
58     pub suggestion: Span,
59     pub replace: &'a str,
60 }
61
62 // methods.rs
63 #[derive(LintDiagnostic)]
64 #[diag(lint_cstring_ptr)]
65 #[note]
66 #[help]
67 pub struct CStringPtr {
68     #[label(as_ptr_label)]
69     pub as_ptr: Span,
70     #[label(unwrap_label)]
71     pub unwrap: Span,
72 }
73
74 // non_ascii_idents.rs
75 #[derive(LintDiagnostic)]
76 #[diag(lint_identifier_non_ascii_char)]
77 pub struct IdentifierNonAsciiChar;
78
79 #[derive(LintDiagnostic)]
80 #[diag(lint_identifier_uncommon_codepoints)]
81 pub struct IdentifierUncommonCodepoints;
82
83 #[derive(LintDiagnostic)]
84 #[diag(lint_confusable_identifier_pair)]
85 pub struct ConfusableIdentifierPair {
86     pub existing_sym: Symbol,
87     pub sym: Symbol,
88     #[label]
89     pub label: Span,
90 }
91
92 #[derive(LintDiagnostic)]
93 #[diag(lint_mixed_script_confusables)]
94 #[note(includes_note)]
95 #[note]
96 pub struct MixedScriptConfusables {
97     pub set: String,
98     pub includes: String,
99 }
100
101 // non_fmt_panic.rs
102 pub struct NonFmtPanicUnused {
103     pub count: usize,
104     pub suggestion: Option<Span>,
105 }
106
107 impl<'a> DecorateLint<'a, ()> for NonFmtPanicUnused {
108     fn decorate_lint<'b>(
109         self,
110         diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>,
111     ) -> &'b mut rustc_errors::DiagnosticBuilder<'a, ()> {
112         diag.set_arg("count", self.count);
113         diag.note(fluent::note);
114         if let Some(span) = self.suggestion {
115             diag.span_suggestion(
116                 span.shrink_to_hi(),
117                 fluent::add_args_suggestion,
118                 ", ...",
119                 Applicability::HasPlaceholders,
120             );
121             diag.span_suggestion(
122                 span.shrink_to_lo(),
123                 fluent::add_fmt_suggestion,
124                 "\"{}\", ",
125                 Applicability::MachineApplicable,
126             );
127         }
128         diag
129     }
130
131     fn msg(&self) -> rustc_errors::DiagnosticMessage {
132         fluent::lint_non_fmt_panic_unused
133     }
134 }
135
136 #[derive(LintDiagnostic)]
137 #[diag(lint_non_fmt_panic_braces)]
138 #[note]
139 pub struct NonFmtPanicBraces {
140     pub count: usize,
141     #[suggestion(code = "\"{{}}\", ", applicability = "machine-applicable")]
142     pub suggestion: Option<Span>,
143 }
144
145 // nonstandard_style.rs
146 #[derive(LintDiagnostic)]
147 #[diag(lint_non_camel_case_type)]
148 pub struct NonCamelCaseType<'a> {
149     pub sort: &'a str,
150     pub name: &'a str,
151     #[subdiagnostic]
152     pub sub: NonCamelCaseTypeSub,
153 }
154
155 #[derive(Subdiagnostic)]
156 pub enum NonCamelCaseTypeSub {
157     #[label(label)]
158     Label {
159         #[primary_span]
160         span: Span,
161     },
162     #[suggestion(suggestion, code = "{replace}", applicability = "maybe-incorrect")]
163     Suggestion {
164         #[primary_span]
165         span: Span,
166         replace: String,
167     },
168 }
169
170 #[derive(LintDiagnostic)]
171 #[diag(lint_non_snake_case)]
172 pub struct NonSnakeCaseDiag<'a> {
173     pub sort: &'a str,
174     pub name: &'a str,
175     pub sc: String,
176     #[subdiagnostic]
177     pub sub: NonSnakeCaseDiagSub,
178 }
179
180 pub enum NonSnakeCaseDiagSub {
181     Label { span: Span },
182     Help,
183     RenameOrConvertSuggestion { span: Span, suggestion: Ident },
184     ConvertSuggestion { span: Span, suggestion: String },
185     SuggestionAndNote { span: Span },
186 }
187
188 impl AddToDiagnostic for NonSnakeCaseDiagSub {
189     fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, _: F)
190     where
191         F: Fn(
192             &mut rustc_errors::Diagnostic,
193             rustc_errors::SubdiagnosticMessage,
194         ) -> rustc_errors::SubdiagnosticMessage,
195     {
196         match self {
197             NonSnakeCaseDiagSub::Label { span } => {
198                 diag.span_label(span, fluent::label);
199             }
200             NonSnakeCaseDiagSub::Help => {
201                 diag.help(fluent::help);
202             }
203             NonSnakeCaseDiagSub::ConvertSuggestion { span, suggestion } => {
204                 diag.span_suggestion(
205                     span,
206                     fluent::convert_suggestion,
207                     suggestion,
208                     Applicability::MaybeIncorrect,
209                 );
210             }
211             NonSnakeCaseDiagSub::RenameOrConvertSuggestion { span, suggestion } => {
212                 diag.span_suggestion(
213                     span,
214                     fluent::rename_or_convert_suggestion,
215                     suggestion,
216                     Applicability::MaybeIncorrect,
217                 );
218             }
219             NonSnakeCaseDiagSub::SuggestionAndNote { span } => {
220                 diag.note(fluent::cannot_convert_note);
221                 diag.span_suggestion(
222                     span,
223                     fluent::rename_suggestion,
224                     "",
225                     Applicability::MaybeIncorrect,
226                 );
227             }
228         }
229     }
230 }
231
232 #[derive(LintDiagnostic)]
233 #[diag(lint_non_upper_case_global)]
234 pub struct NonUpperCaseGlobal<'a> {
235     pub sort: &'a str,
236     pub name: &'a str,
237     #[subdiagnostic]
238     pub sub: NonUpperCaseGlobalSub,
239 }
240
241 #[derive(Subdiagnostic)]
242 pub enum NonUpperCaseGlobalSub {
243     #[label(label)]
244     Label {
245         #[primary_span]
246         span: Span,
247     },
248     #[suggestion(suggestion, code = "{replace}", applicability = "maybe-incorrect")]
249     Suggestion {
250         #[primary_span]
251         span: Span,
252         replace: String,
253     },
254 }
255
256 // noop_method_call.rs
257 #[derive(LintDiagnostic)]
258 #[diag(lint_noop_method_call)]
259 #[note]
260 pub struct NoopMethodCallDiag<'a> {
261     pub method: Symbol,
262     pub receiver_ty: Ty<'a>,
263     #[label]
264     pub label: Span,
265 }
266
267 // pass_by_value.rs
268 #[derive(LintDiagnostic)]
269 #[diag(lint_pass_by_value)]
270 pub struct PassByValueDiag {
271     pub ty: String,
272     #[suggestion(code = "{ty}", applicability = "maybe-incorrect")]
273     pub suggestion: Span,
274 }
275
276 // redundant_semicolon.rs
277 #[derive(LintDiagnostic)]
278 #[diag(lint_redundant_semicolons)]
279 pub struct RedundantSemicolonsDiag {
280     pub multiple: bool,
281     #[suggestion(code = "", applicability = "maybe-incorrect")]
282     pub suggestion: Span,
283 }
284
285 // traits.rs
286 pub struct DropTraitConstraintsDiag<'a> {
287     pub predicate: Predicate<'a>,
288     pub tcx: TyCtxt<'a>,
289     pub def_id: DefId,
290 }
291
292 impl<'a> DecorateLint<'a, ()> for DropTraitConstraintsDiag<'_> {
293     fn decorate_lint<'b>(
294         self,
295         diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>,
296     ) -> &'b mut rustc_errors::DiagnosticBuilder<'a, ()> {
297         diag.set_arg("predicate", self.predicate);
298         diag.set_arg("needs_drop", self.tcx.def_path_str(self.def_id))
299     }
300
301     fn msg(&self) -> rustc_errors::DiagnosticMessage {
302         fluent::lint_drop_trait_constraints
303     }
304 }
305
306 pub struct DropGlue<'a> {
307     pub tcx: TyCtxt<'a>,
308     pub def_id: DefId,
309 }
310
311 impl<'a> DecorateLint<'a, ()> for DropGlue<'_> {
312     fn decorate_lint<'b>(
313         self,
314         diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>,
315     ) -> &'b mut rustc_errors::DiagnosticBuilder<'a, ()> {
316         diag.set_arg("needs_drop", self.tcx.def_path_str(self.def_id))
317     }
318
319     fn msg(&self) -> rustc_errors::DiagnosticMessage {
320         fluent::lint_drop_glue
321     }
322 }
323
324 // types.rs
325 #[derive(LintDiagnostic)]
326 #[diag(lint_range_endpoint_out_of_range)]
327 pub struct RangeEndpointOutOfRange<'a> {
328     pub ty: &'a str,
329     #[suggestion(code = "{start}..={literal}{suffix}", applicability = "machine-applicable")]
330     pub suggestion: Span,
331     pub start: String,
332     pub literal: u128,
333     pub suffix: &'a str,
334 }
335
336 #[derive(LintDiagnostic)]
337 #[diag(lint_overflowing_bin_hex)]
338 pub struct OverflowingBinHex<'a> {
339     pub ty: &'a str,
340     pub lit: String,
341     pub dec: u128,
342     pub actually: String,
343     #[subdiagnostic]
344     pub sign: OverflowingBinHexSign,
345     #[subdiagnostic]
346     pub sub: Option<OverflowingBinHexSub<'a>>,
347 }
348
349 pub enum OverflowingBinHexSign {
350     Positive,
351     Negative,
352 }
353
354 impl AddToDiagnostic for OverflowingBinHexSign {
355     fn add_to_diagnostic_with<F>(self, diag: &mut rustc_errors::Diagnostic, _: F)
356     where
357         F: Fn(
358             &mut rustc_errors::Diagnostic,
359             rustc_errors::SubdiagnosticMessage,
360         ) -> rustc_errors::SubdiagnosticMessage,
361     {
362         match self {
363             OverflowingBinHexSign::Positive => {
364                 diag.note(fluent::positive_note);
365             }
366             OverflowingBinHexSign::Negative => {
367                 diag.note(fluent::negative_note);
368                 diag.note(fluent::negative_becomes_note);
369             }
370         }
371     }
372 }
373
374 #[derive(Subdiagnostic)]
375 pub enum OverflowingBinHexSub<'a> {
376     #[suggestion(
377         suggestion,
378         code = "{sans_suffix}{suggestion_ty}",
379         applicability = "machine-applicable"
380     )]
381     Suggestion {
382         #[primary_span]
383         span: Span,
384         suggestion_ty: &'a str,
385         sans_suffix: &'a str,
386     },
387     #[help(help)]
388     Help { suggestion_ty: &'a str },
389 }
390
391 pub struct OverflowingInt<'a> {
392     pub ty: &'a str,
393     pub lit: String,
394     pub min: i128,
395     pub max: u128,
396     pub suggestion_ty: Option<&'a str>,
397 }
398
399 // FIXME: refactor with `Option<&'a str>` in macro
400 impl<'a> DecorateLint<'a, ()> for OverflowingInt<'_> {
401     fn decorate_lint<'b>(
402         self,
403         diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>,
404     ) -> &'b mut rustc_errors::DiagnosticBuilder<'a, ()> {
405         diag.set_arg("ty", self.ty);
406         diag.set_arg("lit", self.lit);
407         diag.set_arg("min", self.min);
408         diag.set_arg("max", self.max);
409         diag.note(fluent::note);
410         if let Some(suggestion_ty) = self.suggestion_ty {
411             diag.set_arg("suggestion_ty", suggestion_ty);
412             diag.help(fluent::help);
413         }
414         diag
415     }
416
417     fn msg(&self) -> rustc_errors::DiagnosticMessage {
418         fluent::lint_overflowing_int
419     }
420 }
421
422 #[derive(LintDiagnostic)]
423 #[diag(lint_only_cast_u8_to_char)]
424 pub struct OnlyCastu8ToChar {
425     #[suggestion(code = "'\\u{{{literal:X}}}'", applicability = "machine-applicable")]
426     pub span: Span,
427     pub literal: u128,
428 }
429
430 #[derive(LintDiagnostic)]
431 #[diag(lint_overflowing_uint)]
432 #[note]
433 pub struct OverflowingUInt<'a> {
434     pub ty: &'a str,
435     pub lit: String,
436     pub min: u128,
437     pub max: u128,
438 }
439
440 #[derive(LintDiagnostic)]
441 #[diag(lint_overflowing_literal)]
442 #[note]
443 pub struct OverflowingLiteral<'a> {
444     pub ty: &'a str,
445     pub lit: String,
446 }
447
448 #[derive(LintDiagnostic)]
449 #[diag(lint_unused_comparisons)]
450 pub struct UnusedComparisons;
451
452 #[derive(LintDiagnostic)]
453 #[diag(lint_variant_size_differences)]
454 pub struct VariantSizeDifferencesDiag {
455     pub largest: u64,
456 }
457
458 #[derive(LintDiagnostic)]
459 #[diag(lint_atomic_ordering_load)]
460 #[help]
461 pub struct AtomicOrderingLoad;
462
463 #[derive(LintDiagnostic)]
464 #[diag(lint_atomic_ordering_store)]
465 #[help]
466 pub struct AtomicOrderingStore;
467
468 #[derive(LintDiagnostic)]
469 #[diag(lint_atomic_ordering_fence)]
470 #[help]
471 pub struct AtomicOrderingFence;
472
473 #[derive(LintDiagnostic)]
474 #[diag(lint_atomic_ordering_invalid)]
475 #[help]
476 pub struct InvalidAtomicOrderingDiag {
477     pub method: Symbol,
478     #[label]
479     pub fail_order_arg_span: Span,
480 }
481
482 // unused.rs
483 #[derive(LintDiagnostic)]
484 #[diag(lint_unused_op)]
485 pub struct UnusedOp<'a> {
486     pub op: &'a str,
487     #[label]
488     pub label: Span,
489     #[suggestion(style = "verbose", code = "let _ = ", applicability = "machine-applicable")]
490     pub suggestion: Span,
491 }
492
493 #[derive(LintDiagnostic)]
494 #[diag(lint_unused_result)]
495 pub struct UnusedResult<'a> {
496     pub ty: Ty<'a>,
497 }
498
499 // FIXME(davidtwco): this isn't properly translatable becauses of the
500 // pre/post strings
501 #[derive(LintDiagnostic)]
502 #[diag(lint_unused_closure)]
503 #[note]
504 pub struct UnusedClosure<'a> {
505     pub count: usize,
506     pub pre: &'a str,
507     pub post: &'a str,
508 }
509
510 // FIXME(davidtwco): this isn't properly translatable becauses of the
511 // pre/post strings
512 #[derive(LintDiagnostic)]
513 #[diag(lint_unused_generator)]
514 #[note]
515 pub struct UnusedGenerator<'a> {
516     pub count: usize,
517     pub pre: &'a str,
518     pub post: &'a str,
519 }
520
521 // FIXME(davidtwco): this isn't properly translatable becauses of the pre/post
522 // strings
523 pub struct UnusedDef<'a, 'b> {
524     pub pre: &'a str,
525     pub post: &'a str,
526     pub cx: &'a LateContext<'b>,
527     pub def_id: DefId,
528     pub note: Option<Symbol>,
529 }
530
531 // FIXME: refactor with `Option<String>` in macro
532 impl<'a> DecorateLint<'a, ()> for UnusedDef<'_, '_> {
533     fn decorate_lint<'b>(
534         self,
535         diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>,
536     ) -> &'b mut rustc_errors::DiagnosticBuilder<'a, ()> {
537         diag.set_arg("pre", self.pre);
538         diag.set_arg("post", self.post);
539         diag.set_arg("def", self.cx.tcx.def_path_str(self.def_id));
540         // check for #[must_use = "..."]
541         if let Some(note) = self.note {
542             diag.note(note.as_str());
543         }
544         diag
545     }
546
547     fn msg(&self) -> rustc_errors::DiagnosticMessage {
548         fluent::lint_unused_def
549     }
550 }
551
552 #[derive(LintDiagnostic)]
553 #[diag(lint_path_statement_drop)]
554 pub struct PathStatementDrop {
555     #[subdiagnostic]
556     pub sub: PathStatementDropSub,
557 }
558
559 #[derive(Subdiagnostic)]
560 pub enum PathStatementDropSub {
561     #[suggestion(suggestion, code = "drop({snippet});", applicability = "machine-applicable")]
562     Suggestion {
563         #[primary_span]
564         span: Span,
565         snippet: String,
566     },
567     #[help(help)]
568     Help {
569         #[primary_span]
570         span: Span,
571     },
572 }
573
574 #[derive(LintDiagnostic)]
575 #[diag(lint_path_statement_no_effect)]
576 pub struct PathStatementNoEffect;
577
578 #[derive(LintDiagnostic)]
579 #[diag(lint_unused_delim)]
580 pub struct UnusedDelim<'a> {
581     pub delim: &'static str,
582     pub item: &'a str,
583     #[subdiagnostic]
584     pub suggestion: Option<UnusedDelimSuggestion>,
585 }
586
587 #[derive(Subdiagnostic)]
588 #[multipart_suggestion(suggestion, applicability = "machine-applicable")]
589 pub struct UnusedDelimSuggestion {
590     #[suggestion_part(code = "{start_replace}")]
591     pub start_span: Span,
592     pub start_replace: &'static str,
593     #[suggestion_part(code = "{end_replace}")]
594     pub end_span: Span,
595     pub end_replace: &'static str,
596 }
597
598 #[derive(LintDiagnostic)]
599 #[diag(lint_unused_import_braces)]
600 pub struct UnusedImportBracesDiag {
601     pub node: Symbol,
602 }
603
604 #[derive(LintDiagnostic)]
605 #[diag(lint_unused_allocation)]
606 pub struct UnusedAllocationDiag;
607
608 #[derive(LintDiagnostic)]
609 #[diag(lint_unused_allocation_mut)]
610 pub struct UnusedAllocationMutDiag;