rustc_lint/
unused.rs

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