rustc_lint/
unused.rs

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