rustc_lint/
unused.rs

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