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                // Avoid `p0 | .. | pn` if we should.
1194                PatKind::Or(..) if avoid_or => return,
1195                // Avoid `mut x` and `mut x @ p` if we should:
1196                PatKind::Ident(BindingMode::MUT, ..) if avoid_mut => {
1197                    return;
1198                }
1199                // Otherwise proceed with linting.
1200                _ => {}
1201            }
1202            let spans = if !value.span.from_expansion() {
1203                inner
1204                    .span
1205                    .find_ancestor_inside(value.span)
1206                    .map(|inner| (value.span.with_hi(inner.lo()), value.span.with_lo(inner.hi())))
1207            } else {
1208                None
1209            };
1210            self.emit_unused_delims(cx, value.span, spans, "pattern", keep_space, false);
1211        }
1212    }
1213
1214    fn cast_followed_by_lt(&self, expr: &ast::Expr) -> Option<ast::NodeId> {
1215        if let ExprKind::Binary(op, lhs, _rhs) = &expr.kind
1216            && (op.node == ast::BinOpKind::Lt || op.node == ast::BinOpKind::Shl)
1217        {
1218            let mut cur = lhs;
1219            while let ExprKind::Binary(_, _, rhs) = &cur.kind {
1220                cur = rhs;
1221            }
1222
1223            if let ExprKind::Cast(_, ty) = &cur.kind
1224                && let ast::TyKind::Paren(_) = &ty.kind
1225            {
1226                return Some(ty.id);
1227            }
1228        }
1229        None
1230    }
1231}
1232
1233impl EarlyLintPass for UnusedParens {
1234    #[inline]
1235    fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
1236        if let Some(ty_id) = self.cast_followed_by_lt(e) {
1237            self.parens_in_cast_in_lt.push(ty_id);
1238        }
1239
1240        match e.kind {
1241            ExprKind::Let(ref pat, _, _, _) | ExprKind::ForLoop { ref pat, .. } => {
1242                self.check_unused_parens_pat(cx, pat, false, false, (true, true));
1243            }
1244            // We ignore parens in cases like `if (((let Some(0) = Some(1))))` because we already
1245            // handle a hard error for them during AST lowering in `lower_expr_mut`, but we still
1246            // want to complain about things like `if let 42 = (42)`.
1247            ExprKind::If(ref cond, ref block, ref else_)
1248                if matches!(cond.peel_parens().kind, ExprKind::Let(..)) =>
1249            {
1250                self.check_unused_delims_expr(
1251                    cx,
1252                    cond.peel_parens(),
1253                    UnusedDelimsCtx::LetScrutineeExpr,
1254                    true,
1255                    None,
1256                    None,
1257                    true,
1258                );
1259                for stmt in &block.stmts {
1260                    <Self as UnusedDelimLint>::check_stmt(self, cx, stmt);
1261                }
1262                if let Some(e) = else_ {
1263                    <Self as UnusedDelimLint>::check_expr(self, cx, e);
1264                }
1265                return;
1266            }
1267            ExprKind::Match(ref _expr, ref arm, _) => {
1268                for a in arm {
1269                    if let Some(body) = &a.body {
1270                        self.check_unused_delims_expr(
1271                            cx,
1272                            body,
1273                            UnusedDelimsCtx::MatchArmExpr,
1274                            false,
1275                            None,
1276                            None,
1277                            true,
1278                        );
1279                    }
1280                }
1281            }
1282            _ => {}
1283        }
1284
1285        <Self as UnusedDelimLint>::check_expr(self, cx, e)
1286    }
1287
1288    fn check_expr_post(&mut self, _cx: &EarlyContext<'_>, e: &ast::Expr) {
1289        if let Some(ty_id) = self.cast_followed_by_lt(e) {
1290            let id = self
1291                .parens_in_cast_in_lt
1292                .pop()
1293                .expect("check_expr and check_expr_post must balance");
1294            assert_eq!(
1295                id, ty_id,
1296                "check_expr, check_ty, and check_expr_post are called, in that order, by the visitor"
1297            );
1298        }
1299    }
1300
1301    fn check_pat(&mut self, cx: &EarlyContext<'_>, p: &ast::Pat) {
1302        use ast::Mutability;
1303        use ast::PatKind::*;
1304        let keep_space = (false, false);
1305        match &p.kind {
1306            // Do not lint on `(..)` as that will result in the other arms being useless.
1307            Paren(_)
1308            // The other cases do not contain sub-patterns.
1309            | Missing | Wild | Never | Rest | Expr(..) | MacCall(..) | Range(..) | Ident(.., None)
1310            | Path(..) | Err(_) => {},
1311            // These are list-like patterns; parens can always be removed.
1312            TupleStruct(_, _, ps) | Tuple(ps) | Slice(ps) | Or(ps) => for p in ps {
1313                self.check_unused_parens_pat(cx, p, false, false, keep_space);
1314            },
1315            Struct(_, _, fps, _) => for f in fps {
1316                self.check_unused_parens_pat(cx, &f.pat, false, false, keep_space);
1317            },
1318            // Avoid linting on `i @ (p0 | .. | pn)` and `box (p0 | .. | pn)`, #64106.
1319            Ident(.., Some(p)) | Box(p) | Deref(p) | Guard(p, _) => self.check_unused_parens_pat(cx, p, true, false, keep_space),
1320            // Avoid linting on `&(mut x)` as `&mut x` has a different meaning, #55342.
1321            // Also avoid linting on `& mut? (p0 | .. | pn)`, #64106.
1322            // FIXME(pin_ergonomics): check pinned patterns
1323            Ref(p, _, m) => self.check_unused_parens_pat(cx, p, true, *m == Mutability::Not, keep_space),
1324        }
1325    }
1326
1327    fn check_stmt(&mut self, cx: &EarlyContext<'_>, s: &ast::Stmt) {
1328        if let StmtKind::Let(ref local) = s.kind {
1329            self.check_unused_parens_pat(cx, &local.pat, true, false, (true, false));
1330        }
1331
1332        <Self as UnusedDelimLint>::check_stmt(self, cx, s)
1333    }
1334
1335    fn check_param(&mut self, cx: &EarlyContext<'_>, param: &ast::Param) {
1336        self.check_unused_parens_pat(cx, &param.pat, true, false, (false, false));
1337    }
1338
1339    fn check_arm(&mut self, cx: &EarlyContext<'_>, arm: &ast::Arm) {
1340        self.check_unused_parens_pat(cx, &arm.pat, false, false, (false, false));
1341    }
1342
1343    fn check_ty(&mut self, cx: &EarlyContext<'_>, ty: &ast::Ty) {
1344        if let ast::TyKind::Paren(_) = ty.kind
1345            && Some(&ty.id) == self.parens_in_cast_in_lt.last()
1346        {
1347            return;
1348        }
1349        match &ty.kind {
1350            ast::TyKind::Array(_, len) => {
1351                self.check_unused_delims_expr(
1352                    cx,
1353                    &len.value,
1354                    UnusedDelimsCtx::ArrayLenExpr,
1355                    false,
1356                    None,
1357                    None,
1358                    false,
1359                );
1360            }
1361            ast::TyKind::Paren(r) => {
1362                let unused_parens = match &r.kind {
1363                    ast::TyKind::ImplTrait(_, bounds) | ast::TyKind::TraitObject(bounds, _) => {
1364                        match self.in_no_bounds_pos.get(&ty.id) {
1365                            Some(NoBoundsException::None) => false,
1366                            Some(NoBoundsException::OneBound) => bounds.len() <= 1,
1367                            None => true,
1368                        }
1369                    }
1370                    ast::TyKind::FnPtr(b) => {
1371                        !self.with_self_ty_parens || b.generic_params.is_empty()
1372                    }
1373                    _ => true,
1374                };
1375
1376                if unused_parens {
1377                    let spans = (!ty.span.from_expansion())
1378                        .then(|| {
1379                            r.span
1380                                .find_ancestor_inside(ty.span)
1381                                .map(|r| (ty.span.with_hi(r.lo()), ty.span.with_lo(r.hi())))
1382                        })
1383                        .flatten();
1384
1385                    self.emit_unused_delims(cx, ty.span, spans, "type", (false, false), false);
1386                }
1387
1388                self.with_self_ty_parens = false;
1389            }
1390            ast::TyKind::Ref(_, mut_ty) | ast::TyKind::Ptr(mut_ty) => {
1391                // If this type itself appears in no-bounds position, we propagate its
1392                // potentially tighter constraint or risk a false posive (issue 143653).
1393                let own_constraint = self.in_no_bounds_pos.get(&ty.id);
1394                let constraint = match own_constraint {
1395                    Some(NoBoundsException::None) => NoBoundsException::None,
1396                    Some(NoBoundsException::OneBound) => NoBoundsException::OneBound,
1397                    None => NoBoundsException::OneBound,
1398                };
1399                self.in_no_bounds_pos.insert(mut_ty.ty.id, constraint);
1400            }
1401            ast::TyKind::TraitObject(bounds, _) | ast::TyKind::ImplTrait(_, bounds) => {
1402                for i in 0..bounds.len() {
1403                    let is_last = i == bounds.len() - 1;
1404
1405                    if let ast::GenericBound::Trait(poly_trait_ref) = &bounds[i] {
1406                        let fn_with_explicit_ret_ty = if let [.., segment] =
1407                            &*poly_trait_ref.trait_ref.path.segments
1408                            && let Some(args) = segment.args.as_ref()
1409                            && let ast::GenericArgs::Parenthesized(paren_args) = &**args
1410                            && let ast::FnRetTy::Ty(ret_ty) = &paren_args.output
1411                        {
1412                            self.in_no_bounds_pos.insert(
1413                                ret_ty.id,
1414                                if is_last {
1415                                    NoBoundsException::OneBound
1416                                } else {
1417                                    NoBoundsException::None
1418                                },
1419                            );
1420
1421                            true
1422                        } else {
1423                            false
1424                        };
1425
1426                        // In edition 2015, dyn is a contextual keyword and `dyn::foo::Bar` is
1427                        // parsed as a path, so parens are necessary to disambiguate. See
1428                        //  - tests/ui/lint/unused/unused-parens-trait-obj-e2015.rs and
1429                        //  - https://doc.rust-lang.org/reference/types/trait-object.html#r-type.trait-object.syntax-edition2018
1430                        let dyn2015_exception = cx.sess().psess.edition == Edition2015
1431                            && matches!(ty.kind, ast::TyKind::TraitObject(..))
1432                            && i == 0
1433                            && poly_trait_ref
1434                                .trait_ref
1435                                .path
1436                                .segments
1437                                .first()
1438                                .map(|s| s.ident.name == kw::PathRoot)
1439                                .unwrap_or(false);
1440
1441                        if let ast::Parens::Yes = poly_trait_ref.parens
1442                            && (is_last || !fn_with_explicit_ret_ty)
1443                            && !dyn2015_exception
1444                        {
1445                            let s = poly_trait_ref.span;
1446                            let spans = (!s.from_expansion()).then(|| {
1447                                (
1448                                    s.with_hi(s.lo() + rustc_span::BytePos(1)),
1449                                    s.with_lo(s.hi() - rustc_span::BytePos(1)),
1450                                )
1451                            });
1452
1453                            self.emit_unused_delims(
1454                                cx,
1455                                poly_trait_ref.span,
1456                                spans,
1457                                "type",
1458                                (false, false),
1459                                false,
1460                            );
1461                        }
1462                    }
1463                }
1464            }
1465            _ => {}
1466        }
1467    }
1468
1469    fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
1470        <Self as UnusedDelimLint>::check_item(self, cx, item)
1471    }
1472
1473    fn check_item_post(&mut self, _: &EarlyContext<'_>, _: &rustc_ast::Item) {
1474        self.in_no_bounds_pos.clear();
1475    }
1476
1477    fn enter_where_predicate(&mut self, _: &EarlyContext<'_>, pred: &ast::WherePredicate) {
1478        use rustc_ast::{WhereBoundPredicate, WherePredicateKind};
1479        if let WherePredicateKind::BoundPredicate(WhereBoundPredicate {
1480            bounded_ty,
1481            bound_generic_params,
1482            ..
1483        }) = &pred.kind
1484            && let ast::TyKind::Paren(_) = &bounded_ty.kind
1485            && bound_generic_params.is_empty()
1486        {
1487            self.with_self_ty_parens = true;
1488        }
1489    }
1490
1491    fn exit_where_predicate(&mut self, _: &EarlyContext<'_>, _: &ast::WherePredicate) {
1492        assert!(!self.with_self_ty_parens);
1493    }
1494}
1495
1496declare_lint! {
1497    /// The `unused_braces` lint detects unnecessary braces around an
1498    /// expression.
1499    ///
1500    /// ### Example
1501    ///
1502    /// ```rust
1503    /// if { true } {
1504    ///     // ...
1505    /// }
1506    /// ```
1507    ///
1508    /// {{produces}}
1509    ///
1510    /// ### Explanation
1511    ///
1512    /// The braces are not needed, and should be removed. This is the
1513    /// preferred style for writing these expressions.
1514    pub(super) UNUSED_BRACES,
1515    Warn,
1516    "unnecessary braces around an expression"
1517}
1518
1519declare_lint_pass!(UnusedBraces => [UNUSED_BRACES]);
1520
1521impl UnusedDelimLint for UnusedBraces {
1522    const DELIM_STR: &'static str = "braces";
1523
1524    const LINT_EXPR_IN_PATTERN_MATCHING_CTX: bool = false;
1525
1526    fn lint(&self) -> &'static Lint {
1527        UNUSED_BRACES
1528    }
1529
1530    fn check_unused_delims_expr(
1531        &self,
1532        cx: &EarlyContext<'_>,
1533        value: &ast::Expr,
1534        ctx: UnusedDelimsCtx,
1535        followed_by_block: bool,
1536        left_pos: Option<BytePos>,
1537        right_pos: Option<BytePos>,
1538        is_kw: bool,
1539    ) {
1540        match value.kind {
1541            ast::ExprKind::Block(ref inner, None)
1542                if inner.rules == ast::BlockCheckMode::Default =>
1543            {
1544                // emit a warning under the following conditions:
1545                //
1546                // - the block does not have a label
1547                // - the block is not `unsafe`
1548                // - the block contains exactly one expression (do not lint `{ expr; }`)
1549                // - `followed_by_block` is true and the internal expr may contain a `{`
1550                // - the block is not multiline (do not lint multiline match arms)
1551                //      ```
1552                //      match expr {
1553                //          Pattern => {
1554                //              somewhat_long_expression
1555                //          }
1556                //          // ...
1557                //      }
1558                //      ```
1559                // - the block has no attribute and was not created inside a macro
1560                // - if the block is an `anon_const`, the inner expr must be a literal
1561                //   not created by a macro, i.e. do not lint on:
1562                //      ```
1563                //      struct A<const N: usize>;
1564                //      let _: A<{ 2 + 3 }>;
1565                //      let _: A<{produces_literal!()}>;
1566                //      ```
1567                // FIXME(const_generics): handle paths when #67075 is fixed.
1568                if let [stmt] = inner.stmts.as_slice()
1569                    && let ast::StmtKind::Expr(ref expr) = stmt.kind
1570                    && !Self::is_expr_delims_necessary(expr, ctx, followed_by_block)
1571                    && (ctx != UnusedDelimsCtx::AnonConst
1572                        || (matches!(expr.kind, ast::ExprKind::Lit(_))
1573                            && !expr.span.from_expansion()))
1574                    && ctx != UnusedDelimsCtx::ClosureBody
1575                    && !cx.sess().source_map().is_multiline(value.span)
1576                    && value.attrs.is_empty()
1577                    && !value.span.from_expansion()
1578                    && !inner.span.from_expansion()
1579                {
1580                    self.emit_unused_delims_expr(cx, value, ctx, left_pos, right_pos, is_kw)
1581                }
1582            }
1583            ast::ExprKind::Let(_, ref expr, _, _) => {
1584                self.check_unused_delims_expr(
1585                    cx,
1586                    expr,
1587                    UnusedDelimsCtx::LetScrutineeExpr,
1588                    followed_by_block,
1589                    None,
1590                    None,
1591                    false,
1592                );
1593            }
1594            _ => {}
1595        }
1596    }
1597}
1598
1599impl EarlyLintPass for UnusedBraces {
1600    fn check_stmt(&mut self, cx: &EarlyContext<'_>, s: &ast::Stmt) {
1601        <Self as UnusedDelimLint>::check_stmt(self, cx, s)
1602    }
1603
1604    #[inline]
1605    fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
1606        <Self as UnusedDelimLint>::check_expr(self, cx, e);
1607
1608        if let ExprKind::Repeat(_, ref anon_const) = e.kind {
1609            self.check_unused_delims_expr(
1610                cx,
1611                &anon_const.value,
1612                UnusedDelimsCtx::AnonConst,
1613                false,
1614                None,
1615                None,
1616                false,
1617            );
1618        }
1619    }
1620
1621    fn check_generic_arg(&mut self, cx: &EarlyContext<'_>, arg: &ast::GenericArg) {
1622        if let ast::GenericArg::Const(ct) = arg {
1623            self.check_unused_delims_expr(
1624                cx,
1625                &ct.value,
1626                UnusedDelimsCtx::AnonConst,
1627                false,
1628                None,
1629                None,
1630                false,
1631            );
1632        }
1633    }
1634
1635    fn check_variant(&mut self, cx: &EarlyContext<'_>, v: &ast::Variant) {
1636        if let Some(anon_const) = &v.disr_expr {
1637            self.check_unused_delims_expr(
1638                cx,
1639                &anon_const.value,
1640                UnusedDelimsCtx::AnonConst,
1641                false,
1642                None,
1643                None,
1644                false,
1645            );
1646        }
1647    }
1648
1649    fn check_ty(&mut self, cx: &EarlyContext<'_>, ty: &ast::Ty) {
1650        match ty.kind {
1651            ast::TyKind::Array(_, ref len) => {
1652                self.check_unused_delims_expr(
1653                    cx,
1654                    &len.value,
1655                    UnusedDelimsCtx::ArrayLenExpr,
1656                    false,
1657                    None,
1658                    None,
1659                    false,
1660                );
1661            }
1662
1663            ast::TyKind::Typeof(ref anon_const) => {
1664                self.check_unused_delims_expr(
1665                    cx,
1666                    &anon_const.value,
1667                    UnusedDelimsCtx::AnonConst,
1668                    false,
1669                    None,
1670                    None,
1671                    false,
1672                );
1673            }
1674
1675            _ => {}
1676        }
1677    }
1678
1679    fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
1680        <Self as UnusedDelimLint>::check_item(self, cx, item)
1681    }
1682}
1683
1684declare_lint! {
1685    /// The `unused_import_braces` lint catches unnecessary braces around an
1686    /// imported item.
1687    ///
1688    /// ### Example
1689    ///
1690    /// ```rust,compile_fail
1691    /// #![deny(unused_import_braces)]
1692    /// use test::{A};
1693    ///
1694    /// pub mod test {
1695    ///     pub struct A;
1696    /// }
1697    /// # fn main() {}
1698    /// ```
1699    ///
1700    /// {{produces}}
1701    ///
1702    /// ### Explanation
1703    ///
1704    /// If there is only a single item, then remove the braces (`use test::A;`
1705    /// for example).
1706    ///
1707    /// This lint is "allow" by default because it is only enforcing a
1708    /// stylistic choice.
1709    UNUSED_IMPORT_BRACES,
1710    Allow,
1711    "unnecessary braces around an imported item"
1712}
1713
1714declare_lint_pass!(UnusedImportBraces => [UNUSED_IMPORT_BRACES]);
1715
1716impl UnusedImportBraces {
1717    fn check_use_tree(&self, cx: &EarlyContext<'_>, use_tree: &ast::UseTree, item: &ast::Item) {
1718        if let ast::UseTreeKind::Nested { ref items, .. } = use_tree.kind {
1719            // Recursively check nested UseTrees
1720            for (tree, _) in items {
1721                self.check_use_tree(cx, tree, item);
1722            }
1723
1724            // Trigger the lint only if there is one nested item
1725            let [(tree, _)] = items.as_slice() else { return };
1726
1727            // Trigger the lint if the nested item is a non-self single item
1728            let node_name = match tree.kind {
1729                ast::UseTreeKind::Simple(rename) => {
1730                    let orig_ident = tree.prefix.segments.last().unwrap().ident;
1731                    if orig_ident.name == kw::SelfLower {
1732                        return;
1733                    }
1734                    rename.unwrap_or(orig_ident).name
1735                }
1736                ast::UseTreeKind::Glob => sym::asterisk,
1737                ast::UseTreeKind::Nested { .. } => return,
1738            };
1739
1740            cx.emit_span_lint(
1741                UNUSED_IMPORT_BRACES,
1742                item.span,
1743                UnusedImportBracesDiag { node: node_name },
1744            );
1745        }
1746    }
1747}
1748
1749impl EarlyLintPass for UnusedImportBraces {
1750    fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
1751        if let ast::ItemKind::Use(ref use_tree) = item.kind {
1752            self.check_use_tree(cx, use_tree, item);
1753        }
1754    }
1755}
1756
1757declare_lint! {
1758    /// The `unused_allocation` lint detects unnecessary allocations that can
1759    /// be eliminated.
1760    ///
1761    /// ### Example
1762    ///
1763    /// ```rust
1764    /// fn main() {
1765    ///     let a = Box::new([1, 2, 3]).len();
1766    /// }
1767    /// ```
1768    ///
1769    /// {{produces}}
1770    ///
1771    /// ### Explanation
1772    ///
1773    /// When a `box` expression is immediately coerced to a reference, then
1774    /// the allocation is unnecessary, and a reference (using `&` or `&mut`)
1775    /// should be used instead to avoid the allocation.
1776    pub(super) UNUSED_ALLOCATION,
1777    Warn,
1778    "detects unnecessary allocations that can be eliminated"
1779}
1780
1781declare_lint_pass!(UnusedAllocation => [UNUSED_ALLOCATION]);
1782
1783impl<'tcx> LateLintPass<'tcx> for UnusedAllocation {
1784    fn check_expr(&mut self, cx: &LateContext<'_>, e: &hir::Expr<'_>) {
1785        match e.kind {
1786            hir::ExprKind::Call(path_expr, [_])
1787                if let hir::ExprKind::Path(qpath) = &path_expr.kind
1788                    && let Some(did) = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id()
1789                    && cx.tcx.is_diagnostic_item(sym::box_new, did) => {}
1790            _ => return,
1791        }
1792
1793        for adj in cx.typeck_results().expr_adjustments(e) {
1794            if let adjustment::Adjust::Borrow(adjustment::AutoBorrow::Ref(m)) = adj.kind {
1795                match m {
1796                    adjustment::AutoBorrowMutability::Not => {
1797                        cx.emit_span_lint(UNUSED_ALLOCATION, e.span, UnusedAllocationDiag);
1798                    }
1799                    adjustment::AutoBorrowMutability::Mut { .. } => {
1800                        cx.emit_span_lint(UNUSED_ALLOCATION, e.span, UnusedAllocationMutDiag);
1801                    }
1802                };
1803            }
1804        }
1805    }
1806}