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