diff options
| author | Philipp Krones <hello@philkrones.com> | 2025-03-20 22:34:29 +0100 |
|---|---|---|
| committer | Philipp Krones <hello@philkrones.com> | 2025-03-20 22:34:29 +0100 |
| commit | ae31f7a024dbc601b7323d95a086acd70f00a723 (patch) | |
| tree | 6eb5b07deb7bdee6c25ecdd85dd344df49ed53bc /src/tools/clippy/clippy_utils | |
| parent | d8e44b722a93e55cbc9a8188dfbfe3faf1226096 (diff) | |
| parent | 1e5237f4a56ae958af7e5824343eacf737b67083 (diff) | |
Merge commit '1e5237f4a56ae958af7e5824343eacf737b67083' into clippy-subtree-update
Diffstat (limited to 'src/tools/clippy/clippy_utils')
| -rw-r--r-- | src/tools/clippy/clippy_utils/README.md | 4 | ||||
| -rw-r--r-- | src/tools/clippy/clippy_utils/src/ast_utils/mod.rs | 2 | ||||
| -rw-r--r-- | src/tools/clippy/clippy_utils/src/diagnostics.rs | 10 | ||||
| -rw-r--r-- | src/tools/clippy/clippy_utils/src/lib.rs | 45 | ||||
| -rw-r--r-- | src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs | 3 | ||||
| -rw-r--r-- | src/tools/clippy/clippy_utils/src/msrvs.rs | 3 | ||||
| -rw-r--r-- | src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs | 40 | ||||
| -rw-r--r-- | src/tools/clippy/clippy_utils/src/sugg.rs | 41 |
8 files changed, 92 insertions, 56 deletions
diff --git a/src/tools/clippy/clippy_utils/README.md b/src/tools/clippy/clippy_utils/README.md index 5dd31b52f88..7c665b42497 100644 --- a/src/tools/clippy/clippy_utils/README.md +++ b/src/tools/clippy/clippy_utils/README.md @@ -8,7 +8,7 @@ This crate is only guaranteed to build with this `nightly` toolchain: <!-- begin autogenerated nightly --> ``` -nightly-2025-02-27 +nightly-2025-03-20 ``` <!-- end autogenerated nightly --> @@ -30,7 +30,7 @@ Function signatures can change or be removed without replacement without any pri <!-- REUSE-IgnoreStart --> -Copyright 2014-2024 The Rust Project Developers +Copyright 2014-2025 The Rust Project Developers Licensed under the Apache License, Version 2.0 <[https://www.apache.org/licenses/LICENSE-2.0](https://www.apache.org/licenses/LICENSE-2.0)> or the MIT license diff --git a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs index 707312a97f3..edebee289e1 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs @@ -688,7 +688,7 @@ pub fn eq_generics(l: &Generics, r: &Generics) -> bool { pub fn eq_where_predicate(l: &WherePredicate, r: &WherePredicate) -> bool { use WherePredicateKind::*; - over(&l.attrs, &r.attrs, eq_attr) + over(&l.attrs, &r.attrs, eq_attr) && match (&l.kind, &r.kind) { (BoundPredicate(l), BoundPredicate(r)) => { over(&l.bound_generic_params, &r.bound_generic_params, |l, r| { diff --git a/src/tools/clippy/clippy_utils/src/diagnostics.rs b/src/tools/clippy/clippy_utils/src/diagnostics.rs index ddb7a6635e0..292792408c6 100644 --- a/src/tools/clippy/clippy_utils/src/diagnostics.rs +++ b/src/tools/clippy/clippy_utils/src/diagnostics.rs @@ -85,7 +85,7 @@ fn validate_diag(diag: &Diag<'_, impl EmissionGuarantee>) { /// This is needed for `#[allow]` and `#[expect]` attributes to work on the node /// highlighted in the displayed warning. /// -/// If you're unsure which function you should use, you can test if the `#[allow]` attribute works +/// If you're unsure which function you should use, you can test if the `#[expect]` attribute works /// where you would expect it to. /// If it doesn't, you likely need to use [`span_lint_hir`] instead. /// @@ -128,7 +128,7 @@ pub fn span_lint<T: LintContext>(cx: &T, lint: &'static Lint, sp: impl Into<Mult /// This is needed for `#[allow]` and `#[expect]` attributes to work on the node /// highlighted in the displayed warning. /// -/// If you're unsure which function you should use, you can test if the `#[allow]` attribute works +/// If you're unsure which function you should use, you can test if the `#[expect]` attribute works /// where you would expect it to. /// If it doesn't, you likely need to use [`span_lint_hir_and_then`] instead. /// @@ -183,7 +183,7 @@ pub fn span_lint_and_help<T: LintContext>( /// This is needed for `#[allow]` and `#[expect]` attributes to work on the node /// highlighted in the displayed warning. /// -/// If you're unsure which function you should use, you can test if the `#[allow]` attribute works +/// If you're unsure which function you should use, you can test if the `#[expect]` attribute works /// where you would expect it to. /// If it doesn't, you likely need to use [`span_lint_hir_and_then`] instead. /// @@ -241,7 +241,7 @@ pub fn span_lint_and_note<T: LintContext>( /// This is needed for `#[allow]` and `#[expect]` attributes to work on the node /// highlighted in the displayed warning. /// -/// If you're unsure which function you should use, you can test if the `#[allow]` attribute works +/// If you're unsure which function you should use, you can test if the `#[expect]` attribute works /// where you would expect it to. /// If it doesn't, you likely need to use [`span_lint_hir_and_then`] instead. pub fn span_lint_and_then<C, S, M, F>(cx: &C, lint: &'static Lint, sp: S, msg: M, f: F) @@ -358,7 +358,7 @@ pub fn span_lint_hir_and_then( /// This is needed for `#[allow]` and `#[expect]` attributes to work on the node /// highlighted in the displayed warning. /// -/// If you're unsure which function you should use, you can test if the `#[allow]` attribute works +/// If you're unsure which function you should use, you can test if the `#[expect]` attribute works /// where you would expect it to. /// If it doesn't, you likely need to use [`span_lint_hir_and_then`] instead. /// diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index eb4e1a7722f..1307ff79bc5 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -106,10 +106,10 @@ use rustc_hir::hir_id::{HirIdMap, HirIdSet}; use rustc_hir::intravisit::{FnKind, Visitor, walk_expr}; use rustc_hir::{ self as hir, Arm, BindingMode, Block, BlockCheckMode, Body, ByRef, Closure, ConstArgKind, ConstContext, - Destination, Expr, ExprField, ExprKind, FnDecl, FnRetTy, GenericArgs, HirId, Impl, ImplItem, ImplItemKind, - ImplItemRef, Item, ItemKind, LangItem, LetStmt, MatchSource, Mutability, Node, OwnerId, OwnerNode, Param, Pat, - PatExpr, PatExprKind, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitFn, TraitItem, TraitItemKind, - TraitItemRef, TraitRef, TyKind, UnOp, def, + Destination, Expr, ExprField, ExprKind, FnDecl, FnRetTy, GenericArg, GenericArgs, HirId, Impl, ImplItem, + ImplItemKind, ImplItemRef, Item, ItemKind, LangItem, LetStmt, MatchSource, Mutability, Node, OwnerId, OwnerNode, + Param, Pat, PatExpr, PatExprKind, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitFn, TraitItem, + TraitItemKind, TraitItemRef, TraitRef, TyKind, UnOp, def, }; use rustc_lexer::{TokenKind, tokenize}; use rustc_lint::{LateContext, Level, Lint, LintContext}; @@ -434,7 +434,7 @@ pub fn qpath_generic_tys<'tcx>(qpath: &QPath<'tcx>) -> impl Iterator<Item = &'tc .map_or(&[][..], |a| a.args) .iter() .filter_map(|a| match a { - hir::GenericArg::Type(ty) => Some(ty.as_unambig_ty()), + GenericArg::Type(ty) => Some(ty.as_unambig_ty()), _ => None, }) } @@ -1420,8 +1420,7 @@ pub fn get_item_name(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<Symbol> { let parent_id = cx.tcx.hir_get_parent_item(expr.hir_id).def_id; match cx.tcx.hir_node_by_def_id(parent_id) { Node::Item(item) => item.kind.ident().map(|ident| ident.name), - Node::TraitItem(TraitItem { ident, .. }) - | Node::ImplItem(ImplItem { ident, .. }) => Some(ident.name), + Node::TraitItem(TraitItem { ident, .. }) | Node::ImplItem(ImplItem { ident, .. }) => Some(ident.name), _ => None, } } @@ -2334,6 +2333,18 @@ pub fn is_expr_final_block_expr(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool { matches!(tcx.parent_hir_node(expr.hir_id), Node::Block(..)) } +/// Checks if the expression is a temporary value. +// This logic is the same as the one used in rustc's `check_named_place_expr function`. +// https://github.com/rust-lang/rust/blob/3ed2a10d173d6c2e0232776af338ca7d080b1cd4/compiler/rustc_hir_typeck/src/expr.rs#L482-L499 +pub fn is_expr_temporary_value(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + !expr.is_place_expr(|base| { + cx.typeck_results() + .adjustments() + .get(base.hir_id) + .is_some_and(|x| x.iter().any(|adj| matches!(adj.kind, Adjust::Deref(_)))) + }) +} + pub fn std_or_core(cx: &LateContext<'_>) -> Option<&'static str> { if !is_no_std_crate(cx) { Some("std") @@ -3548,7 +3559,7 @@ pub fn is_block_like(expr: &Expr<'_>) -> bool { pub fn binary_expr_needs_parentheses(expr: &Expr<'_>) -> bool { fn contains_block(expr: &Expr<'_>, is_operand: bool) -> bool { match expr.kind { - ExprKind::Binary(_, lhs, _) => contains_block(lhs, true), + ExprKind::Binary(_, lhs, _) | ExprKind::Cast(lhs, _) => contains_block(lhs, true), _ if is_block_like(expr) => is_operand, _ => false, } @@ -3695,3 +3706,21 @@ pub fn is_mutable(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { true } } + +/// Peel `Option<…>` from `hir_ty` as long as the HIR name is `Option` and it corresponds to the +/// `core::Option<_>` type. +pub fn peel_hir_ty_options<'tcx>(cx: &LateContext<'tcx>, mut hir_ty: &'tcx hir::Ty<'tcx>) -> &'tcx hir::Ty<'tcx> { + let Some(option_def_id) = cx.tcx.get_diagnostic_item(sym::Option) else { + return hir_ty; + }; + while let TyKind::Path(QPath::Resolved(None, path)) = hir_ty.kind + && let Some(segment) = path.segments.last() + && segment.ident.name == sym::Option + && let Res::Def(DefKind::Enum, def_id) = segment.res + && def_id == option_def_id + && let [GenericArg::Type(arg_ty)] = segment.args().args + { + hir_ty = arg_ty.as_unambig_ty(); + } + hir_ty +} diff --git a/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs b/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs index db07b640416..152b4272c26 100644 --- a/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs +++ b/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs @@ -6,8 +6,7 @@ use rustc_index::bit_set::DenseBitSet; use rustc_lint::LateContext; use rustc_middle::mir::visit::Visitor as _; use rustc_middle::mir::{self, Mutability}; -use rustc_middle::ty::TypeVisitor; -use rustc_middle::ty::{self, TyCtxt}; +use rustc_middle::ty::{self, TyCtxt, TypeVisitor}; use rustc_mir_dataflow::impls::MaybeStorageLive; use rustc_mir_dataflow::{Analysis, ResultsCursor}; use std::borrow::Cow; diff --git a/src/tools/clippy/clippy_utils/src/msrvs.rs b/src/tools/clippy/clippy_utils/src/msrvs.rs index 0316de172de..86f4f190b95 100644 --- a/src/tools/clippy/clippy_utils/src/msrvs.rs +++ b/src/tools/clippy/clippy_utils/src/msrvs.rs @@ -33,7 +33,7 @@ msrv_aliases! { 1,76,0 { PTR_FROM_REF, OPTION_RESULT_INSPECT } 1,75,0 { OPTION_AS_SLICE } 1,74,0 { REPR_RUST, IO_ERROR_OTHER } - 1,73,0 { MANUAL_DIV_CEIL } + 1,73,0 { DIV_CEIL } 1,71,0 { TUPLE_ARRAY_CONVERSIONS, BUILD_HASHER_HASH_ONE } 1,70,0 { OPTION_RESULT_IS_VARIANT_AND, BINARY_HEAP_RETAIN } 1,68,0 { PATH_MAIN_SEPARATOR_STR } @@ -74,6 +74,7 @@ msrv_aliases! { 1,17,0 { FIELD_INIT_SHORTHAND, STATIC_IN_CONST, EXPECT_ERR } 1,16,0 { STR_REPEAT } 1,15,0 { MAYBE_BOUND_IN_WHERE } + 1,13,0 { QUESTION_MARK_OPERATOR } } /// `#[clippy::msrv]` attributes are rarely used outside of Clippy's test suite, as a basic diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index 8e6f4d4a317..5d0401010db 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -395,24 +395,32 @@ fn check_terminator<'tcx>( fn is_stable_const_fn(cx: &LateContext<'_>, def_id: DefId, msrv: Msrv) -> bool { cx.tcx.is_const_fn(def_id) - && cx.tcx.lookup_const_stability(def_id).is_none_or(|const_stab| { - if let rustc_attr_parsing::StabilityLevel::Stable { since, .. } = const_stab.level { - // Checking MSRV is manually necessary because `rustc` has no such concept. This entire - // function could be removed if `rustc` provided a MSRV-aware version of `is_stable_const_fn`. - // as a part of an unimplemented MSRV check https://github.com/rust-lang/rust/issues/65262. + && cx + .tcx + .lookup_const_stability(def_id) + .or_else(|| { + cx.tcx + .trait_of_item(def_id) + .and_then(|trait_def_id| cx.tcx.lookup_const_stability(trait_def_id)) + }) + .is_none_or(|const_stab| { + if let rustc_attr_parsing::StabilityLevel::Stable { since, .. } = const_stab.level { + // Checking MSRV is manually necessary because `rustc` has no such concept. This entire + // function could be removed if `rustc` provided a MSRV-aware version of `is_stable_const_fn`. + // as a part of an unimplemented MSRV check https://github.com/rust-lang/rust/issues/65262. - let const_stab_rust_version = match since { - StableSince::Version(version) => version, - StableSince::Current => RustcVersion::CURRENT, - StableSince::Err => return false, - }; + let const_stab_rust_version = match since { + StableSince::Version(version) => version, + StableSince::Current => RustcVersion::CURRENT, + StableSince::Err => return false, + }; - msrv.meets(cx, const_stab_rust_version) - } else { - // Unstable const fn, check if the feature is enabled. - cx.tcx.features().enabled(const_stab.feature) && msrv.current(cx).is_none() - } - }) + msrv.meets(cx, const_stab_rust_version) + } else { + // Unstable const fn, check if the feature is enabled. + cx.tcx.features().enabled(const_stab.feature) && msrv.current(cx).is_none() + } + }) } fn is_ty_const_destruct<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, body: &Body<'tcx>) -> bool { diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs index 9cc66593dcc..68a1de96a35 100644 --- a/src/tools/clippy/clippy_utils/src/sugg.rs +++ b/src/tools/clippy/clippy_utils/src/sugg.rs @@ -4,8 +4,8 @@ use crate::source::{snippet, snippet_opt, snippet_with_applicability, snippet_with_context}; use crate::ty::expr_sig; use crate::{get_parent_expr_for_hir, higher}; -use rustc_ast::util::parser::AssocOp; use rustc_ast::ast; +use rustc_ast::util::parser::AssocOp; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::{Closure, ExprKind, HirId, MutTy, TyKind}; @@ -444,7 +444,7 @@ impl<'a> Not for Sugg<'a> { type Output = Sugg<'a>; fn not(self) -> Sugg<'a> { use AssocOp::Binary; - use ast::BinOpKind::{Eq, Gt, Ge, Lt, Le, Ne}; + use ast::BinOpKind::{Eq, Ge, Gt, Le, Lt, Ne}; if let Sugg::BinOp(op, lhs, rhs) = self { let to_op = match op { @@ -515,10 +515,10 @@ pub fn make_assoc(op: AssocOp, lhs: &Sugg<'_>, rhs: &Sugg<'_>) -> Sugg<'static> op, AssocOp::Binary( ast::BinOpKind::Add - | ast::BinOpKind::Sub - | ast::BinOpKind::Mul - | ast::BinOpKind::Div - | ast::BinOpKind::Rem + | ast::BinOpKind::Sub + | ast::BinOpKind::Mul + | ast::BinOpKind::Div + | ast::BinOpKind::Rem ) ) } @@ -578,10 +578,8 @@ enum Associativity { /// associative. #[must_use] fn associativity(op: AssocOp) -> Associativity { + use ast::BinOpKind::{Add, And, BitAnd, BitOr, BitXor, Div, Eq, Ge, Gt, Le, Lt, Mul, Ne, Or, Rem, Shl, Shr, Sub}; use rustc_ast::util::parser::AssocOp::{Assign, AssignOp, Binary, Cast, Range}; - use ast::BinOpKind::{ - Add, BitAnd, BitOr, BitXor, Div, Eq, Gt, Ge, And, Or, Lt, Le, Rem, Mul, Ne, Shl, Shr, Sub, - }; match op { Assign | AssignOp(_) => Associativity::Right, @@ -994,6 +992,7 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> { mod test { use super::Sugg; + use rustc_ast as ast; use rustc_ast::util::parser::AssocOp; use std::borrow::Cow; @@ -1011,15 +1010,15 @@ mod test { #[test] fn binop_maybe_par() { - let sugg = Sugg::BinOp(AssocOp::Add, "1".into(), "1".into()); + let sugg = Sugg::BinOp(AssocOp::Binary(ast::BinOpKind::Add), "1".into(), "1".into()); assert_eq!("(1 + 1)", sugg.maybe_par().to_string()); - let sugg = Sugg::BinOp(AssocOp::Add, "(1 + 1)".into(), "(1 + 1)".into()); + let sugg = Sugg::BinOp(AssocOp::Binary(ast::BinOpKind::Add), "(1 + 1)".into(), "(1 + 1)".into()); assert_eq!("((1 + 1) + (1 + 1))", sugg.maybe_par().to_string()); } #[test] fn not_op() { - use AssocOp::{Add, Equal, Greater, GreaterEqual, LAnd, LOr, Less, LessEqual, NotEqual}; + use ast::BinOpKind::{Add, And, Eq, Ge, Gt, Le, Lt, Ne, Or}; fn test_not(op: AssocOp, correct: &str) { let sugg = Sugg::BinOp(op, "x".into(), "y".into()); @@ -1027,16 +1026,16 @@ mod test { } // Invert the comparison operator. - test_not(Equal, "x != y"); - test_not(NotEqual, "x == y"); - test_not(Less, "x >= y"); - test_not(LessEqual, "x > y"); - test_not(Greater, "x <= y"); - test_not(GreaterEqual, "x < y"); + test_not(AssocOp::Binary(Eq), "x != y"); + test_not(AssocOp::Binary(Ne), "x == y"); + test_not(AssocOp::Binary(Lt), "x >= y"); + test_not(AssocOp::Binary(Le), "x > y"); + test_not(AssocOp::Binary(Gt), "x <= y"); + test_not(AssocOp::Binary(Ge), "x < y"); // Other operators are inverted like !(..). - test_not(Add, "!(x + y)"); - test_not(LAnd, "!(x && y)"); - test_not(LOr, "!(x || y)"); + test_not(AssocOp::Binary(Add), "!(x + y)"); + test_not(AssocOp::Binary(And), "!(x && y)"); + test_not(AssocOp::Binary(Or), "!(x || y)"); } } |
