rustc_lint/
unused.rs

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