rustc_lint/
unused.rs

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