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