Auto merge of #138761 - flip1995:clippy-subtree-update, r=Manishearth

Clippy subtree update

r? `@Manishearth`

Cargo.lock update is because of the `ui_test` dependency bump in Clippy.
This commit is contained in:
bors 2025-03-21 04:59:08 +00:00
commit 4f2ee8ca2a
215 changed files with 4612 additions and 1145 deletions

View file

@ -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.
///

View file

@ -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
}

View file

@ -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;

View file

@ -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

View file

@ -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 {

View file

@ -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)");
}
}