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