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