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