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