]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_lint/src/unused.rs
Rollup merge of #98126 - fortanix:raoul/mitigate_stale_data_vulnerability, r=cuviper
[rust.git] / compiler / rustc_lint / src / unused.rs
1 use crate::Lint;
2 use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
3 use rustc_ast as ast;
4 use rustc_ast::util::{classify, parser};
5 use rustc_ast::{ExprKind, StmtKind};
6 use rustc_errors::{pluralize, Applicability, MultiSpan};
7 use rustc_hir as hir;
8 use rustc_hir::def::{DefKind, Res};
9 use rustc_hir::def_id::DefId;
10 use rustc_middle::ty::adjustment;
11 use rustc_middle::ty::{self, Ty};
12 use rustc_span::symbol::Symbol;
13 use rustc_span::symbol::{kw, sym};
14 use rustc_span::{BytePos, Span, DUMMY_SP};
15
16 declare_lint! {
17     /// The `unused_must_use` lint detects unused result of a type flagged as
18     /// `#[must_use]`.
19     ///
20     /// ### Example
21     ///
22     /// ```rust
23     /// fn returns_result() -> Result<(), ()> {
24     ///     Ok(())
25     /// }
26     ///
27     /// fn main() {
28     ///     returns_result();
29     /// }
30     /// ```
31     ///
32     /// {{produces}}
33     ///
34     /// ### Explanation
35     ///
36     /// The `#[must_use]` attribute is an indicator that it is a mistake to
37     /// ignore the value. See [the reference] for more details.
38     ///
39     /// [the reference]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute
40     pub UNUSED_MUST_USE,
41     Warn,
42     "unused result of a type flagged as `#[must_use]`",
43     report_in_external_macro
44 }
45
46 declare_lint! {
47     /// The `unused_results` lint checks for the unused result of an
48     /// expression in a statement.
49     ///
50     /// ### Example
51     ///
52     /// ```rust,compile_fail
53     /// #![deny(unused_results)]
54     /// fn foo<T>() -> T { panic!() }
55     ///
56     /// fn main() {
57     ///     foo::<usize>();
58     /// }
59     /// ```
60     ///
61     /// {{produces}}
62     ///
63     /// ### Explanation
64     ///
65     /// Ignoring the return value of a function may indicate a mistake. In
66     /// cases were it is almost certain that the result should be used, it is
67     /// recommended to annotate the function with the [`must_use` attribute].
68     /// Failure to use such a return value will trigger the [`unused_must_use`
69     /// lint] which is warn-by-default. The `unused_results` lint is
70     /// essentially the same, but triggers for *all* return values.
71     ///
72     /// This lint is "allow" by default because it can be noisy, and may not be
73     /// an actual problem. For example, calling the `remove` method of a `Vec`
74     /// or `HashMap` returns the previous value, which you may not care about.
75     /// Using this lint would require explicitly ignoring or discarding such
76     /// values.
77     ///
78     /// [`must_use` attribute]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute
79     /// [`unused_must_use` lint]: warn-by-default.html#unused-must-use
80     pub UNUSED_RESULTS,
81     Allow,
82     "unused result of an expression in a statement"
83 }
84
85 declare_lint_pass!(UnusedResults => [UNUSED_MUST_USE, UNUSED_RESULTS]);
86
87 impl<'tcx> LateLintPass<'tcx> for UnusedResults {
88     fn check_stmt(&mut self, cx: &LateContext<'_>, s: &hir::Stmt<'_>) {
89         let expr = match s.kind {
90             hir::StmtKind::Semi(ref expr) => &**expr,
91             _ => return,
92         };
93
94         if let hir::ExprKind::Ret(..) = expr.kind {
95             return;
96         }
97
98         let ty = cx.typeck_results().expr_ty(&expr);
99         let type_permits_lack_of_use = check_must_use_ty(cx, ty, &expr, s.span, "", "", 1);
100
101         let mut fn_warned = false;
102         let mut op_warned = false;
103         let maybe_def_id = match expr.kind {
104             hir::ExprKind::Call(ref callee, _) => {
105                 match callee.kind {
106                     hir::ExprKind::Path(ref qpath) => {
107                         match cx.qpath_res(qpath, callee.hir_id) {
108                             Res::Def(DefKind::Fn | DefKind::AssocFn, def_id) => Some(def_id),
109                             // `Res::Local` if it was a closure, for which we
110                             // do not currently support must-use linting
111                             _ => None,
112                         }
113                     }
114                     _ => None,
115                 }
116             }
117             hir::ExprKind::MethodCall(..) => cx.typeck_results().type_dependent_def_id(expr.hir_id),
118             _ => None,
119         };
120         if let Some(def_id) = maybe_def_id {
121             fn_warned = check_must_use_def(cx, def_id, s.span, "return value of ", "");
122         } else if type_permits_lack_of_use {
123             // We don't warn about unused unit or uninhabited types.
124             // (See https://github.com/rust-lang/rust/issues/43806 for details.)
125             return;
126         }
127
128         let must_use_op = match expr.kind {
129             // Hardcoding operators here seemed more expedient than the
130             // refactoring that would be needed to look up the `#[must_use]`
131             // attribute which does exist on the comparison trait methods
132             hir::ExprKind::Binary(bin_op, ..) => match bin_op.node {
133                 hir::BinOpKind::Eq
134                 | hir::BinOpKind::Lt
135                 | hir::BinOpKind::Le
136                 | hir::BinOpKind::Ne
137                 | hir::BinOpKind::Ge
138                 | hir::BinOpKind::Gt => Some("comparison"),
139                 hir::BinOpKind::Add
140                 | hir::BinOpKind::Sub
141                 | hir::BinOpKind::Div
142                 | hir::BinOpKind::Mul
143                 | hir::BinOpKind::Rem => Some("arithmetic operation"),
144                 hir::BinOpKind::And | hir::BinOpKind::Or => Some("logical operation"),
145                 hir::BinOpKind::BitXor
146                 | hir::BinOpKind::BitAnd
147                 | hir::BinOpKind::BitOr
148                 | hir::BinOpKind::Shl
149                 | hir::BinOpKind::Shr => Some("bitwise operation"),
150             },
151             hir::ExprKind::AddrOf(..) => Some("borrow"),
152             hir::ExprKind::Unary(..) => Some("unary operation"),
153             _ => None,
154         };
155
156         if let Some(must_use_op) = must_use_op {
157             cx.struct_span_lint(UNUSED_MUST_USE, expr.span, |lint| {
158                 let mut lint = lint.build(&format!("unused {} that must be used", must_use_op));
159                 lint.span_label(expr.span, &format!("the {} produces a value", must_use_op));
160                 lint.span_suggestion_verbose(
161                     expr.span.shrink_to_lo(),
162                     "use `let _ = ...` to ignore the resulting value",
163                     "let _ = ",
164                     Applicability::MachineApplicable,
165                 );
166                 lint.emit();
167             });
168             op_warned = true;
169         }
170
171         if !(type_permits_lack_of_use || fn_warned || op_warned) {
172             cx.struct_span_lint(UNUSED_RESULTS, s.span, |lint| {
173                 lint.build(&format!("unused result of type `{}`", ty)).emit();
174             });
175         }
176
177         // Returns whether an error has been emitted (and thus another does not need to be later).
178         fn check_must_use_ty<'tcx>(
179             cx: &LateContext<'tcx>,
180             ty: Ty<'tcx>,
181             expr: &hir::Expr<'_>,
182             span: Span,
183             descr_pre: &str,
184             descr_post: &str,
185             plural_len: usize,
186         ) -> bool {
187             if ty.is_unit()
188                 || cx.tcx.is_ty_uninhabited_from(
189                     cx.tcx.parent_module(expr.hir_id).to_def_id(),
190                     ty,
191                     cx.param_env,
192                 )
193             {
194                 return true;
195             }
196
197             let plural_suffix = pluralize!(plural_len);
198
199             match *ty.kind() {
200                 ty::Adt(..) if ty.is_box() => {
201                     let boxed_ty = ty.boxed_ty();
202                     let descr_pre = &format!("{}boxed ", descr_pre);
203                     check_must_use_ty(cx, boxed_ty, expr, span, descr_pre, descr_post, plural_len)
204                 }
205                 ty::Adt(def, _) => check_must_use_def(cx, def.did(), span, descr_pre, descr_post),
206                 ty::Opaque(def, _) => {
207                     let mut has_emitted = false;
208                     for &(predicate, _) in cx.tcx.explicit_item_bounds(def) {
209                         // We only look at the `DefId`, so it is safe to skip the binder here.
210                         if let ty::PredicateKind::Trait(ref poly_trait_predicate) =
211                             predicate.kind().skip_binder()
212                         {
213                             let def_id = poly_trait_predicate.trait_ref.def_id;
214                             let descr_pre =
215                                 &format!("{}implementer{} of ", descr_pre, plural_suffix,);
216                             if check_must_use_def(cx, def_id, span, descr_pre, descr_post) {
217                                 has_emitted = true;
218                                 break;
219                             }
220                         }
221                     }
222                     has_emitted
223                 }
224                 ty::Dynamic(binder, _) => {
225                     let mut has_emitted = false;
226                     for predicate in binder.iter() {
227                         if let ty::ExistentialPredicate::Trait(ref trait_ref) =
228                             predicate.skip_binder()
229                         {
230                             let def_id = trait_ref.def_id;
231                             let descr_post =
232                                 &format!(" trait object{}{}", plural_suffix, descr_post,);
233                             if check_must_use_def(cx, def_id, span, descr_pre, descr_post) {
234                                 has_emitted = true;
235                                 break;
236                             }
237                         }
238                     }
239                     has_emitted
240                 }
241                 ty::Tuple(ref tys) => {
242                     let mut has_emitted = false;
243                     let comps = if let hir::ExprKind::Tup(comps) = expr.kind {
244                         debug_assert_eq!(comps.len(), tys.len());
245                         comps
246                     } else {
247                         &[]
248                     };
249                     for (i, ty) in tys.iter().enumerate() {
250                         let descr_post = &format!(" in tuple element {}", i);
251                         let e = comps.get(i).unwrap_or(expr);
252                         let span = e.span;
253                         if check_must_use_ty(cx, ty, e, span, descr_pre, descr_post, plural_len) {
254                             has_emitted = true;
255                         }
256                     }
257                     has_emitted
258                 }
259                 ty::Array(ty, len) => match len.try_eval_usize(cx.tcx, cx.param_env) {
260                     // If the array is empty we don't lint, to avoid false positives
261                     Some(0) | None => false,
262                     // If the array is definitely non-empty, we can do `#[must_use]` checking.
263                     Some(n) => {
264                         let descr_pre = &format!("{}array{} of ", descr_pre, plural_suffix,);
265                         check_must_use_ty(cx, ty, expr, span, descr_pre, descr_post, n as usize + 1)
266                     }
267                 },
268                 ty::Closure(..) => {
269                     cx.struct_span_lint(UNUSED_MUST_USE, span, |lint| {
270                         let mut err = lint.build(&format!(
271                             "unused {}closure{}{} that must be used",
272                             descr_pre, plural_suffix, descr_post,
273                         ));
274                         err.note("closures are lazy and do nothing unless called");
275                         err.emit();
276                     });
277                     true
278                 }
279                 ty::Generator(..) => {
280                     cx.struct_span_lint(UNUSED_MUST_USE, span, |lint| {
281                         let mut err = lint.build(&format!(
282                             "unused {}generator{}{} that must be used",
283                             descr_pre, plural_suffix, descr_post,
284                         ));
285                         err.note("generators are lazy and do nothing unless resumed");
286                         err.emit();
287                     });
288                     true
289                 }
290                 _ => false,
291             }
292         }
293
294         // Returns whether an error has been emitted (and thus another does not need to be later).
295         // FIXME: Args desc_{pre,post}_path could be made lazy by taking Fn() -> &str, but this
296         // would make calling it a big awkward. Could also take String (so args are moved), but
297         // this would still require a copy into the format string, which would only be executed
298         // when needed.
299         fn check_must_use_def(
300             cx: &LateContext<'_>,
301             def_id: DefId,
302             span: Span,
303             descr_pre_path: &str,
304             descr_post_path: &str,
305         ) -> bool {
306             if let Some(attr) = cx.tcx.get_attr(def_id, sym::must_use) {
307                 cx.struct_span_lint(UNUSED_MUST_USE, span, |lint| {
308                     let msg = format!(
309                         "unused {}`{}`{} that must be used",
310                         descr_pre_path,
311                         cx.tcx.def_path_str(def_id),
312                         descr_post_path
313                     );
314                     let mut err = lint.build(&msg);
315                     // check for #[must_use = "..."]
316                     if let Some(note) = attr.value_str() {
317                         err.note(note.as_str());
318                     }
319                     err.emit();
320                 });
321                 true
322             } else {
323                 false
324             }
325         }
326     }
327 }
328
329 declare_lint! {
330     /// The `path_statements` lint detects path statements with no effect.
331     ///
332     /// ### Example
333     ///
334     /// ```rust
335     /// let x = 42;
336     ///
337     /// x;
338     /// ```
339     ///
340     /// {{produces}}
341     ///
342     /// ### Explanation
343     ///
344     /// It is usually a mistake to have a statement that has no effect.
345     pub PATH_STATEMENTS,
346     Warn,
347     "path statements with no effect"
348 }
349
350 declare_lint_pass!(PathStatements => [PATH_STATEMENTS]);
351
352 impl<'tcx> LateLintPass<'tcx> for PathStatements {
353     fn check_stmt(&mut self, cx: &LateContext<'_>, s: &hir::Stmt<'_>) {
354         if let hir::StmtKind::Semi(expr) = s.kind {
355             if let hir::ExprKind::Path(_) = expr.kind {
356                 cx.struct_span_lint(PATH_STATEMENTS, s.span, |lint| {
357                     let ty = cx.typeck_results().expr_ty(expr);
358                     if ty.needs_drop(cx.tcx, cx.param_env) {
359                         let mut lint = lint.build("path statement drops value");
360                         if let Ok(snippet) = cx.sess().source_map().span_to_snippet(expr.span) {
361                             lint.span_suggestion(
362                                 s.span,
363                                 "use `drop` to clarify the intent",
364                                 format!("drop({});", snippet),
365                                 Applicability::MachineApplicable,
366                             );
367                         } else {
368                             lint.span_help(s.span, "use `drop` to clarify the intent");
369                         }
370                         lint.emit();
371                     } else {
372                         lint.build("path statement with no effect").emit();
373                     }
374                 });
375             }
376         }
377     }
378 }
379
380 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
381 enum UnusedDelimsCtx {
382     FunctionArg,
383     MethodArg,
384     AssignedValue,
385     AssignedValueLetElse,
386     IfCond,
387     WhileCond,
388     ForIterExpr,
389     MatchScrutineeExpr,
390     ReturnValue,
391     BlockRetValue,
392     LetScrutineeExpr,
393     ArrayLenExpr,
394     AnonConst,
395 }
396
397 impl From<UnusedDelimsCtx> for &'static str {
398     fn from(ctx: UnusedDelimsCtx) -> &'static str {
399         match ctx {
400             UnusedDelimsCtx::FunctionArg => "function argument",
401             UnusedDelimsCtx::MethodArg => "method argument",
402             UnusedDelimsCtx::AssignedValue | UnusedDelimsCtx::AssignedValueLetElse => {
403                 "assigned value"
404             }
405             UnusedDelimsCtx::IfCond => "`if` condition",
406             UnusedDelimsCtx::WhileCond => "`while` condition",
407             UnusedDelimsCtx::ForIterExpr => "`for` iterator expression",
408             UnusedDelimsCtx::MatchScrutineeExpr => "`match` scrutinee expression",
409             UnusedDelimsCtx::ReturnValue => "`return` value",
410             UnusedDelimsCtx::BlockRetValue => "block return value",
411             UnusedDelimsCtx::LetScrutineeExpr => "`let` scrutinee expression",
412             UnusedDelimsCtx::ArrayLenExpr | UnusedDelimsCtx::AnonConst => "const expression",
413         }
414     }
415 }
416
417 /// Used by both `UnusedParens` and `UnusedBraces` to prevent code duplication.
418 trait UnusedDelimLint {
419     const DELIM_STR: &'static str;
420
421     /// Due to `ref` pattern, there can be a difference between using
422     /// `{ expr }` and `expr` in pattern-matching contexts. This means
423     /// that we should only lint `unused_parens` and not `unused_braces`
424     /// in this case.
425     ///
426     /// ```rust
427     /// let mut a = 7;
428     /// let ref b = { a }; // We actually borrow a copy of `a` here.
429     /// a += 1; // By mutating `a` we invalidate any borrows of `a`.
430     /// assert_eq!(b + 1, a); // `b` does not borrow `a`, so we can still use it here.
431     /// ```
432     const LINT_EXPR_IN_PATTERN_MATCHING_CTX: bool;
433
434     // this cannot be a constant is it refers to a static.
435     fn lint(&self) -> &'static Lint;
436
437     fn check_unused_delims_expr(
438         &self,
439         cx: &EarlyContext<'_>,
440         value: &ast::Expr,
441         ctx: UnusedDelimsCtx,
442         followed_by_block: bool,
443         left_pos: Option<BytePos>,
444         right_pos: Option<BytePos>,
445     );
446
447     fn is_expr_delims_necessary(
448         inner: &ast::Expr,
449         followed_by_block: bool,
450         followed_by_else: bool,
451     ) -> bool {
452         if followed_by_else {
453             match inner.kind {
454                 ast::ExprKind::Binary(op, ..) if op.node.lazy() => return true,
455                 _ if classify::expr_trailing_brace(inner).is_some() => return true,
456                 _ => {}
457             }
458         }
459
460         // Prevent false-positives in cases like `fn x() -> u8 { ({ 0 } + 1) }`
461         let lhs_needs_parens = {
462             let mut innermost = inner;
463             loop {
464                 innermost = match &innermost.kind {
465                     ExprKind::Binary(_, lhs, _rhs) => lhs,
466                     ExprKind::Call(fn_, _params) => fn_,
467                     ExprKind::Cast(expr, _ty) => expr,
468                     ExprKind::Type(expr, _ty) => expr,
469                     ExprKind::Index(base, _subscript) => base,
470                     _ => break false,
471                 };
472                 if !classify::expr_requires_semi_to_be_stmt(innermost) {
473                     break true;
474                 }
475             }
476         };
477
478         lhs_needs_parens
479             || (followed_by_block
480                 && match &inner.kind {
481                     ExprKind::Ret(_) | ExprKind::Break(..) | ExprKind::Yield(..) => true,
482                     ExprKind::Range(_lhs, Some(rhs), _limits) => {
483                         matches!(rhs.kind, ExprKind::Block(..))
484                     }
485                     _ => parser::contains_exterior_struct_lit(&inner),
486                 })
487     }
488
489     fn emit_unused_delims_expr(
490         &self,
491         cx: &EarlyContext<'_>,
492         value: &ast::Expr,
493         ctx: UnusedDelimsCtx,
494         left_pos: Option<BytePos>,
495         right_pos: Option<BytePos>,
496     ) {
497         let spans = match value.kind {
498             ast::ExprKind::Block(ref block, None) if block.stmts.len() > 0 => {
499                 let start = block.stmts[0].span;
500                 let end = block.stmts[block.stmts.len() - 1].span;
501                 if value.span.from_expansion() || start.from_expansion() || end.from_expansion() {
502                     (
503                         value.span.with_hi(value.span.lo() + BytePos(1)),
504                         value.span.with_lo(value.span.hi() - BytePos(1)),
505                     )
506                 } else {
507                     (value.span.with_hi(start.lo()), value.span.with_lo(end.hi()))
508                 }
509             }
510             ast::ExprKind::Paren(ref expr) => {
511                 if value.span.from_expansion() || expr.span.from_expansion() {
512                     (
513                         value.span.with_hi(value.span.lo() + BytePos(1)),
514                         value.span.with_lo(value.span.hi() - BytePos(1)),
515                     )
516                 } else {
517                     (value.span.with_hi(expr.span.lo()), value.span.with_lo(expr.span.hi()))
518                 }
519             }
520             _ => return,
521         };
522         let keep_space = (
523             left_pos.map_or(false, |s| s >= value.span.lo()),
524             right_pos.map_or(false, |s| s <= value.span.hi()),
525         );
526         self.emit_unused_delims(cx, spans, ctx.into(), keep_space);
527     }
528
529     fn emit_unused_delims(
530         &self,
531         cx: &EarlyContext<'_>,
532         spans: (Span, Span),
533         msg: &str,
534         keep_space: (bool, bool),
535     ) {
536         // FIXME(flip1995): Quick and dirty fix for #70814. This should be fixed in rustdoc
537         // properly.
538         if spans.0 == DUMMY_SP || spans.1 == DUMMY_SP {
539             return;
540         }
541
542         cx.struct_span_lint(self.lint(), MultiSpan::from(vec![spans.0, spans.1]), |lint| {
543             let span_msg = format!("unnecessary {} around {}", Self::DELIM_STR, msg);
544             let mut err = lint.build(&span_msg);
545             let replacement = vec![
546                 (spans.0, if keep_space.0 { " ".into() } else { "".into() }),
547                 (spans.1, if keep_space.1 { " ".into() } else { "".into() }),
548             ];
549             let suggestion = format!("remove these {}", Self::DELIM_STR);
550             err.multipart_suggestion(&suggestion, replacement, Applicability::MachineApplicable);
551             err.emit();
552         });
553     }
554
555     fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
556         use rustc_ast::ExprKind::*;
557         let (value, ctx, followed_by_block, left_pos, right_pos) = match e.kind {
558             // Do not lint `unused_braces` in `if let` expressions.
559             If(ref cond, ref block, _)
560                 if !matches!(cond.kind, Let(_, _, _))
561                     || Self::LINT_EXPR_IN_PATTERN_MATCHING_CTX =>
562             {
563                 let left = e.span.lo() + rustc_span::BytePos(2);
564                 let right = block.span.lo();
565                 (cond, UnusedDelimsCtx::IfCond, true, Some(left), Some(right))
566             }
567
568             // Do not lint `unused_braces` in `while let` expressions.
569             While(ref cond, ref block, ..)
570                 if !matches!(cond.kind, Let(_, _, _))
571                     || Self::LINT_EXPR_IN_PATTERN_MATCHING_CTX =>
572             {
573                 let left = e.span.lo() + rustc_span::BytePos(5);
574                 let right = block.span.lo();
575                 (cond, UnusedDelimsCtx::WhileCond, true, Some(left), Some(right))
576             }
577
578             ForLoop(_, ref cond, ref block, ..) => {
579                 (cond, UnusedDelimsCtx::ForIterExpr, true, None, Some(block.span.lo()))
580             }
581
582             Match(ref head, _) if Self::LINT_EXPR_IN_PATTERN_MATCHING_CTX => {
583                 let left = e.span.lo() + rustc_span::BytePos(5);
584                 (head, UnusedDelimsCtx::MatchScrutineeExpr, true, Some(left), None)
585             }
586
587             Ret(Some(ref value)) => {
588                 let left = e.span.lo() + rustc_span::BytePos(3);
589                 (value, UnusedDelimsCtx::ReturnValue, false, Some(left), None)
590             }
591
592             Assign(_, ref value, _) | AssignOp(.., ref value) => {
593                 (value, UnusedDelimsCtx::AssignedValue, false, None, None)
594             }
595             // either function/method call, or something this lint doesn't care about
596             ref call_or_other => {
597                 let (args_to_check, ctx) = match *call_or_other {
598                     Call(_, ref args) => (&args[..], UnusedDelimsCtx::FunctionArg),
599                     // first "argument" is self (which sometimes needs delims)
600                     MethodCall(_, ref args, _) => (&args[1..], UnusedDelimsCtx::MethodArg),
601                     // actual catch-all arm
602                     _ => {
603                         return;
604                     }
605                 };
606                 // Don't lint if this is a nested macro expansion: otherwise, the lint could
607                 // trigger in situations that macro authors shouldn't have to care about, e.g.,
608                 // when a parenthesized token tree matched in one macro expansion is matched as
609                 // an expression in another and used as a fn/method argument (Issue #47775)
610                 if e.span.ctxt().outer_expn_data().call_site.from_expansion() {
611                     return;
612                 }
613                 for arg in args_to_check {
614                     self.check_unused_delims_expr(cx, arg, ctx, false, None, None);
615                 }
616                 return;
617             }
618         };
619         self.check_unused_delims_expr(cx, &value, ctx, followed_by_block, left_pos, right_pos);
620     }
621
622     fn check_stmt(&mut self, cx: &EarlyContext<'_>, s: &ast::Stmt) {
623         match s.kind {
624             StmtKind::Local(ref local) if Self::LINT_EXPR_IN_PATTERN_MATCHING_CTX => {
625                 if let Some((init, els)) = local.kind.init_else_opt() {
626                     let ctx = match els {
627                         None => UnusedDelimsCtx::AssignedValue,
628                         Some(_) => UnusedDelimsCtx::AssignedValueLetElse,
629                     };
630                     self.check_unused_delims_expr(cx, init, ctx, false, None, None);
631                 }
632             }
633             StmtKind::Expr(ref expr) => {
634                 self.check_unused_delims_expr(
635                     cx,
636                     &expr,
637                     UnusedDelimsCtx::BlockRetValue,
638                     false,
639                     None,
640                     None,
641                 );
642             }
643             _ => {}
644         }
645     }
646
647     fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
648         use ast::ItemKind::*;
649
650         if let Const(.., Some(expr)) | Static(.., Some(expr)) = &item.kind {
651             self.check_unused_delims_expr(
652                 cx,
653                 expr,
654                 UnusedDelimsCtx::AssignedValue,
655                 false,
656                 None,
657                 None,
658             );
659         }
660     }
661 }
662
663 declare_lint! {
664     /// The `unused_parens` lint detects `if`, `match`, `while` and `return`
665     /// with parentheses; they do not need them.
666     ///
667     /// ### Examples
668     ///
669     /// ```rust
670     /// if(true) {}
671     /// ```
672     ///
673     /// {{produces}}
674     ///
675     /// ### Explanation
676     ///
677     /// The parentheses are not needed, and should be removed. This is the
678     /// preferred style for writing these expressions.
679     pub(super) UNUSED_PARENS,
680     Warn,
681     "`if`, `match`, `while` and `return` do not need parentheses"
682 }
683
684 declare_lint_pass!(UnusedParens => [UNUSED_PARENS]);
685
686 impl UnusedDelimLint for UnusedParens {
687     const DELIM_STR: &'static str = "parentheses";
688
689     const LINT_EXPR_IN_PATTERN_MATCHING_CTX: bool = true;
690
691     fn lint(&self) -> &'static Lint {
692         UNUSED_PARENS
693     }
694
695     fn check_unused_delims_expr(
696         &self,
697         cx: &EarlyContext<'_>,
698         value: &ast::Expr,
699         ctx: UnusedDelimsCtx,
700         followed_by_block: bool,
701         left_pos: Option<BytePos>,
702         right_pos: Option<BytePos>,
703     ) {
704         match value.kind {
705             ast::ExprKind::Paren(ref inner) => {
706                 let followed_by_else = ctx == UnusedDelimsCtx::AssignedValueLetElse;
707                 if !Self::is_expr_delims_necessary(inner, followed_by_block, followed_by_else)
708                     && value.attrs.is_empty()
709                     && !value.span.from_expansion()
710                     && (ctx != UnusedDelimsCtx::LetScrutineeExpr
711                         || !matches!(inner.kind, ast::ExprKind::Binary(
712                                 rustc_span::source_map::Spanned { node, .. },
713                                 _,
714                                 _,
715                             ) if node.lazy()))
716                 {
717                     self.emit_unused_delims_expr(cx, value, ctx, left_pos, right_pos)
718                 }
719             }
720             ast::ExprKind::Let(_, ref expr, _) => {
721                 self.check_unused_delims_expr(
722                     cx,
723                     expr,
724                     UnusedDelimsCtx::LetScrutineeExpr,
725                     followed_by_block,
726                     None,
727                     None,
728                 );
729             }
730             _ => {}
731         }
732     }
733 }
734
735 impl UnusedParens {
736     fn check_unused_parens_pat(
737         &self,
738         cx: &EarlyContext<'_>,
739         value: &ast::Pat,
740         avoid_or: bool,
741         avoid_mut: bool,
742     ) {
743         use ast::{BindingMode, Mutability, PatKind};
744
745         if let PatKind::Paren(inner) = &value.kind {
746             match inner.kind {
747                 // The lint visitor will visit each subpattern of `p`. We do not want to lint
748                 // any range pattern no matter where it occurs in the pattern. For something like
749                 // `&(a..=b)`, there is a recursive `check_pat` on `a` and `b`, but we will assume
750                 // that if there are unnecessary parens they serve a purpose of readability.
751                 PatKind::Range(..) => return,
752                 // Avoid `p0 | .. | pn` if we should.
753                 PatKind::Or(..) if avoid_or => return,
754                 // Avoid `mut x` and `mut x @ p` if we should:
755                 PatKind::Ident(BindingMode::ByValue(Mutability::Mut), ..) if avoid_mut => return,
756                 // Otherwise proceed with linting.
757                 _ => {}
758             }
759             let spans = if value.span.from_expansion() || inner.span.from_expansion() {
760                 (
761                     value.span.with_hi(value.span.lo() + BytePos(1)),
762                     value.span.with_lo(value.span.hi() - BytePos(1)),
763                 )
764             } else {
765                 (value.span.with_hi(inner.span.lo()), value.span.with_lo(inner.span.hi()))
766             };
767             self.emit_unused_delims(cx, spans, "pattern", (false, false));
768         }
769     }
770 }
771
772 impl EarlyLintPass for UnusedParens {
773     fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
774         match e.kind {
775             ExprKind::Let(ref pat, _, _) | ExprKind::ForLoop(ref pat, ..) => {
776                 self.check_unused_parens_pat(cx, pat, false, false);
777             }
778             // We ignore parens in cases like `if (((let Some(0) = Some(1))))` because we already
779             // handle a hard error for them during AST lowering in `lower_expr_mut`, but we still
780             // want to complain about things like `if let 42 = (42)`.
781             ExprKind::If(ref cond, ref block, ref else_)
782                 if matches!(cond.peel_parens().kind, ExprKind::Let(..)) =>
783             {
784                 self.check_unused_delims_expr(
785                     cx,
786                     cond.peel_parens(),
787                     UnusedDelimsCtx::LetScrutineeExpr,
788                     true,
789                     None,
790                     None,
791                 );
792                 for stmt in &block.stmts {
793                     <Self as UnusedDelimLint>::check_stmt(self, cx, stmt);
794                 }
795                 if let Some(e) = else_ {
796                     <Self as UnusedDelimLint>::check_expr(self, cx, e);
797                 }
798                 return;
799             }
800             _ => {}
801         }
802
803         <Self as UnusedDelimLint>::check_expr(self, cx, e)
804     }
805
806     fn check_pat(&mut self, cx: &EarlyContext<'_>, p: &ast::Pat) {
807         use ast::{Mutability, PatKind::*};
808         match &p.kind {
809             // Do not lint on `(..)` as that will result in the other arms being useless.
810             Paren(_)
811             // The other cases do not contain sub-patterns.
812             | Wild | Rest | Lit(..) | MacCall(..) | Range(..) | Ident(.., None) | Path(..) => {},
813             // These are list-like patterns; parens can always be removed.
814             TupleStruct(_, _, ps) | Tuple(ps) | Slice(ps) | Or(ps) => for p in ps {
815                 self.check_unused_parens_pat(cx, p, false, false);
816             },
817             Struct(_, _, fps, _) => for f in fps {
818                 self.check_unused_parens_pat(cx, &f.pat, false, false);
819             },
820             // Avoid linting on `i @ (p0 | .. | pn)` and `box (p0 | .. | pn)`, #64106.
821             Ident(.., Some(p)) | Box(p) => self.check_unused_parens_pat(cx, p, true, false),
822             // Avoid linting on `&(mut x)` as `&mut x` has a different meaning, #55342.
823             // Also avoid linting on `& mut? (p0 | .. | pn)`, #64106.
824             Ref(p, m) => self.check_unused_parens_pat(cx, p, true, *m == Mutability::Not),
825         }
826     }
827
828     fn check_stmt(&mut self, cx: &EarlyContext<'_>, s: &ast::Stmt) {
829         if let StmtKind::Local(ref local) = s.kind {
830             self.check_unused_parens_pat(cx, &local.pat, true, false);
831         }
832
833         <Self as UnusedDelimLint>::check_stmt(self, cx, s)
834     }
835
836     fn check_param(&mut self, cx: &EarlyContext<'_>, param: &ast::Param) {
837         self.check_unused_parens_pat(cx, &param.pat, true, false);
838     }
839
840     fn check_arm(&mut self, cx: &EarlyContext<'_>, arm: &ast::Arm) {
841         self.check_unused_parens_pat(cx, &arm.pat, false, false);
842     }
843
844     fn check_ty(&mut self, cx: &EarlyContext<'_>, ty: &ast::Ty) {
845         if let ast::TyKind::Paren(r) = &ty.kind {
846             match &r.kind {
847                 ast::TyKind::TraitObject(..) => {}
848                 ast::TyKind::ImplTrait(_, bounds) if bounds.len() > 1 => {}
849                 ast::TyKind::Array(_, len) => {
850                     self.check_unused_delims_expr(
851                         cx,
852                         &len.value,
853                         UnusedDelimsCtx::ArrayLenExpr,
854                         false,
855                         None,
856                         None,
857                     );
858                 }
859                 _ => {
860                     let spans = if ty.span.from_expansion() || r.span.from_expansion() {
861                         (
862                             ty.span.with_hi(ty.span.lo() + BytePos(1)),
863                             ty.span.with_lo(ty.span.hi() - BytePos(1)),
864                         )
865                     } else {
866                         (ty.span.with_hi(r.span.lo()), ty.span.with_lo(r.span.hi()))
867                     };
868                     self.emit_unused_delims(cx, spans, "type", (false, false));
869                 }
870             }
871         }
872     }
873
874     fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
875         <Self as UnusedDelimLint>::check_item(self, cx, item)
876     }
877 }
878
879 declare_lint! {
880     /// The `unused_braces` lint detects unnecessary braces around an
881     /// expression.
882     ///
883     /// ### Example
884     ///
885     /// ```rust
886     /// if { true } {
887     ///     // ...
888     /// }
889     /// ```
890     ///
891     /// {{produces}}
892     ///
893     /// ### Explanation
894     ///
895     /// The braces are not needed, and should be removed. This is the
896     /// preferred style for writing these expressions.
897     pub(super) UNUSED_BRACES,
898     Warn,
899     "unnecessary braces around an expression"
900 }
901
902 declare_lint_pass!(UnusedBraces => [UNUSED_BRACES]);
903
904 impl UnusedDelimLint for UnusedBraces {
905     const DELIM_STR: &'static str = "braces";
906
907     const LINT_EXPR_IN_PATTERN_MATCHING_CTX: bool = false;
908
909     fn lint(&self) -> &'static Lint {
910         UNUSED_BRACES
911     }
912
913     fn check_unused_delims_expr(
914         &self,
915         cx: &EarlyContext<'_>,
916         value: &ast::Expr,
917         ctx: UnusedDelimsCtx,
918         followed_by_block: bool,
919         left_pos: Option<BytePos>,
920         right_pos: Option<BytePos>,
921     ) {
922         match value.kind {
923             ast::ExprKind::Block(ref inner, None)
924                 if inner.rules == ast::BlockCheckMode::Default =>
925             {
926                 // emit a warning under the following conditions:
927                 //
928                 // - the block does not have a label
929                 // - the block is not `unsafe`
930                 // - the block contains exactly one expression (do not lint `{ expr; }`)
931                 // - `followed_by_block` is true and the internal expr may contain a `{`
932                 // - the block is not multiline (do not lint multiline match arms)
933                 //      ```
934                 //      match expr {
935                 //          Pattern => {
936                 //              somewhat_long_expression
937                 //          }
938                 //          // ...
939                 //      }
940                 //      ```
941                 // - the block has no attribute and was not created inside a macro
942                 // - if the block is an `anon_const`, the inner expr must be a literal
943                 //      (do not lint `struct A<const N: usize>; let _: A<{ 2 + 3 }>;`)
944                 //
945                 // FIXME(const_generics): handle paths when #67075 is fixed.
946                 if let [stmt] = inner.stmts.as_slice() {
947                     if let ast::StmtKind::Expr(ref expr) = stmt.kind {
948                         if !Self::is_expr_delims_necessary(expr, followed_by_block, false)
949                             && (ctx != UnusedDelimsCtx::AnonConst
950                                 || matches!(expr.kind, ast::ExprKind::Lit(_)))
951                             && !cx.sess().source_map().is_multiline(value.span)
952                             && value.attrs.is_empty()
953                             && !value.span.from_expansion()
954                         {
955                             self.emit_unused_delims_expr(cx, value, ctx, left_pos, right_pos)
956                         }
957                     }
958                 }
959             }
960             ast::ExprKind::Let(_, ref expr, _) => {
961                 self.check_unused_delims_expr(
962                     cx,
963                     expr,
964                     UnusedDelimsCtx::LetScrutineeExpr,
965                     followed_by_block,
966                     None,
967                     None,
968                 );
969             }
970             _ => {}
971         }
972     }
973 }
974
975 impl EarlyLintPass for UnusedBraces {
976     fn check_stmt(&mut self, cx: &EarlyContext<'_>, s: &ast::Stmt) {
977         <Self as UnusedDelimLint>::check_stmt(self, cx, s)
978     }
979
980     fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
981         <Self as UnusedDelimLint>::check_expr(self, cx, e);
982
983         if let ExprKind::Repeat(_, ref anon_const) = e.kind {
984             self.check_unused_delims_expr(
985                 cx,
986                 &anon_const.value,
987                 UnusedDelimsCtx::AnonConst,
988                 false,
989                 None,
990                 None,
991             );
992         }
993     }
994
995     fn check_generic_arg(&mut self, cx: &EarlyContext<'_>, arg: &ast::GenericArg) {
996         if let ast::GenericArg::Const(ct) = arg {
997             self.check_unused_delims_expr(
998                 cx,
999                 &ct.value,
1000                 UnusedDelimsCtx::AnonConst,
1001                 false,
1002                 None,
1003                 None,
1004             );
1005         }
1006     }
1007
1008     fn check_variant(&mut self, cx: &EarlyContext<'_>, v: &ast::Variant) {
1009         if let Some(anon_const) = &v.disr_expr {
1010             self.check_unused_delims_expr(
1011                 cx,
1012                 &anon_const.value,
1013                 UnusedDelimsCtx::AnonConst,
1014                 false,
1015                 None,
1016                 None,
1017             );
1018         }
1019     }
1020
1021     fn check_ty(&mut self, cx: &EarlyContext<'_>, ty: &ast::Ty) {
1022         match ty.kind {
1023             ast::TyKind::Array(_, ref len) => {
1024                 self.check_unused_delims_expr(
1025                     cx,
1026                     &len.value,
1027                     UnusedDelimsCtx::ArrayLenExpr,
1028                     false,
1029                     None,
1030                     None,
1031                 );
1032             }
1033
1034             ast::TyKind::Typeof(ref anon_const) => {
1035                 self.check_unused_delims_expr(
1036                     cx,
1037                     &anon_const.value,
1038                     UnusedDelimsCtx::AnonConst,
1039                     false,
1040                     None,
1041                     None,
1042                 );
1043             }
1044
1045             _ => {}
1046         }
1047     }
1048
1049     fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
1050         <Self as UnusedDelimLint>::check_item(self, cx, item)
1051     }
1052 }
1053
1054 declare_lint! {
1055     /// The `unused_import_braces` lint catches unnecessary braces around an
1056     /// imported item.
1057     ///
1058     /// ### Example
1059     ///
1060     /// ```rust,compile_fail
1061     /// #![deny(unused_import_braces)]
1062     /// use test::{A};
1063     ///
1064     /// pub mod test {
1065     ///     pub struct A;
1066     /// }
1067     /// # fn main() {}
1068     /// ```
1069     ///
1070     /// {{produces}}
1071     ///
1072     /// ### Explanation
1073     ///
1074     /// If there is only a single item, then remove the braces (`use test::A;`
1075     /// for example).
1076     ///
1077     /// This lint is "allow" by default because it is only enforcing a
1078     /// stylistic choice.
1079     UNUSED_IMPORT_BRACES,
1080     Allow,
1081     "unnecessary braces around an imported item"
1082 }
1083
1084 declare_lint_pass!(UnusedImportBraces => [UNUSED_IMPORT_BRACES]);
1085
1086 impl UnusedImportBraces {
1087     fn check_use_tree(&self, cx: &EarlyContext<'_>, use_tree: &ast::UseTree, item: &ast::Item) {
1088         if let ast::UseTreeKind::Nested(ref items) = use_tree.kind {
1089             // Recursively check nested UseTrees
1090             for &(ref tree, _) in items {
1091                 self.check_use_tree(cx, tree, item);
1092             }
1093
1094             // Trigger the lint only if there is one nested item
1095             if items.len() != 1 {
1096                 return;
1097             }
1098
1099             // Trigger the lint if the nested item is a non-self single item
1100             let node_name = match items[0].0.kind {
1101                 ast::UseTreeKind::Simple(rename, ..) => {
1102                     let orig_ident = items[0].0.prefix.segments.last().unwrap().ident;
1103                     if orig_ident.name == kw::SelfLower {
1104                         return;
1105                     }
1106                     rename.unwrap_or(orig_ident).name
1107                 }
1108                 ast::UseTreeKind::Glob => Symbol::intern("*"),
1109                 ast::UseTreeKind::Nested(_) => return,
1110             };
1111
1112             cx.struct_span_lint(UNUSED_IMPORT_BRACES, item.span, |lint| {
1113                 lint.build(&format!("braces around {} is unnecessary", node_name)).emit();
1114             });
1115         }
1116     }
1117 }
1118
1119 impl EarlyLintPass for UnusedImportBraces {
1120     fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
1121         if let ast::ItemKind::Use(ref use_tree) = item.kind {
1122             self.check_use_tree(cx, use_tree, item);
1123         }
1124     }
1125 }
1126
1127 declare_lint! {
1128     /// The `unused_allocation` lint detects unnecessary allocations that can
1129     /// be eliminated.
1130     ///
1131     /// ### Example
1132     ///
1133     /// ```rust
1134     /// #![feature(box_syntax)]
1135     /// fn main() {
1136     ///     let a = (box [1, 2, 3]).len();
1137     /// }
1138     /// ```
1139     ///
1140     /// {{produces}}
1141     ///
1142     /// ### Explanation
1143     ///
1144     /// When a `box` expression is immediately coerced to a reference, then
1145     /// the allocation is unnecessary, and a reference (using `&` or `&mut`)
1146     /// should be used instead to avoid the allocation.
1147     pub(super) UNUSED_ALLOCATION,
1148     Warn,
1149     "detects unnecessary allocations that can be eliminated"
1150 }
1151
1152 declare_lint_pass!(UnusedAllocation => [UNUSED_ALLOCATION]);
1153
1154 impl<'tcx> LateLintPass<'tcx> for UnusedAllocation {
1155     fn check_expr(&mut self, cx: &LateContext<'_>, e: &hir::Expr<'_>) {
1156         match e.kind {
1157             hir::ExprKind::Box(_) => {}
1158             _ => return,
1159         }
1160
1161         for adj in cx.typeck_results().expr_adjustments(e) {
1162             if let adjustment::Adjust::Borrow(adjustment::AutoBorrow::Ref(_, m)) = adj.kind {
1163                 cx.struct_span_lint(UNUSED_ALLOCATION, e.span, |lint| {
1164                     let msg = match m {
1165                         adjustment::AutoBorrowMutability::Not => {
1166                             "unnecessary allocation, use `&` instead"
1167                         }
1168                         adjustment::AutoBorrowMutability::Mut { .. } => {
1169                             "unnecessary allocation, use `&mut` instead"
1170                         }
1171                     };
1172                     lint.build(msg).emit();
1173                 });
1174             }
1175         }
1176     }
1177 }