rustc_lint/
unused.rs

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