r? @ghost

changelog: none
This commit is contained in:
Philipp Krones 2025-06-26 17:34:27 +00:00 committed by GitHub
commit c950602c01
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
54 changed files with 277 additions and 213 deletions

View file

@ -1,6 +1,6 @@
[package]
name = "clippy"
version = "0.1.89"
version = "0.1.90"
description = "A bunch of helpful lints to avoid common pitfalls in Rust"
repository = "https://github.com/rust-lang/rust-clippy"
readme = "README.md"
@ -59,6 +59,7 @@ rustc_tools_util = { path = "rustc_tools_util", version = "0.4.2" }
[features]
integration = ["dep:tempfile"]
internal = ["dep:clippy_lints_internal", "dep:tempfile"]
jemalloc = []
[package.metadata.rust-analyzer]
# This package uses #[feature(rustc_private)]

View file

@ -1,6 +1,6 @@
[package]
name = "clippy_config"
version = "0.1.89"
version = "0.1.90"
edition = "2024"
publish = false

View file

@ -386,17 +386,13 @@ pub fn read_deprecated_lints() -> (Vec<DeprecatedLint>, Vec<RenamedLint>) {
/// Removes the line splices and surrounding quotes from a string literal
fn parse_str_lit(s: &str) -> String {
let (s, mode) = if let Some(s) = s.strip_prefix("r") {
(s.trim_matches('#'), rustc_literal_escaper::Mode::RawStr)
} else {
(s, rustc_literal_escaper::Mode::Str)
};
let s = s.strip_prefix("r").unwrap_or(s).trim_matches('#');
let s = s
.strip_prefix('"')
.and_then(|s| s.strip_suffix('"'))
.unwrap_or_else(|| panic!("expected quoted string, found `{s}`"));
let mut res = String::with_capacity(s.len());
rustc_literal_escaper::unescape_unicode(s, mode, &mut |_, ch| {
rustc_literal_escaper::unescape_str(s, &mut |_, ch| {
if let Ok(ch) = ch {
res.push(ch);
}

View file

@ -1,6 +1,6 @@
[package]
name = "clippy_lints"
version = "0.1.89"
version = "0.1.90"
description = "A bunch of helpful lints to avoid common pitfalls in Rust"
repository = "https://github.com/rust-lang/rust-clippy"
readme = "README.md"

View file

@ -1,29 +1,22 @@
use super::INLINE_ALWAYS;
use super::utils::is_word;
use clippy_utils::diagnostics::span_lint;
use rustc_attr_data_structures::{AttributeKind, InlineAttr, find_attr};
use rustc_hir::Attribute;
use rustc_lint::LateContext;
use rustc_span::Span;
use rustc_span::symbol::Symbol;
use rustc_span::{Span, sym};
pub(super) fn check(cx: &LateContext<'_>, span: Span, name: Symbol, attrs: &[Attribute]) {
if span.from_expansion() {
return;
}
for attr in attrs {
if let Some(values) = attr.meta_item_list() {
if values.len() != 1 || !attr.has_name(sym::inline) {
continue;
}
if is_word(&values[0], sym::always) {
span_lint(
cx,
INLINE_ALWAYS,
attr.span(),
format!("you have declared `#[inline(always)]` on `{name}`. This is usually a bad idea"),
);
}
}
if let Some(span) = find_attr!(attrs, AttributeKind::Inline(InlineAttr::Always, span) => *span) {
span_lint(
cx,
INLINE_ALWAYS,
span,
format!("you have declared `#[inline(always)]` on `{name}`. This is usually a bad idea"),
);
}
}

View file

@ -56,7 +56,7 @@ fn is_impl_not_trait_with_bool_out<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -
.and_then(|trait_id| {
cx.tcx.associated_items(trait_id).find_by_ident_and_kind(
cx.tcx,
Ident::from_str("Output"),
Ident::with_dummy_span(sym::Output),
ty::AssocTag::Type,
trait_id,
)

View file

@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::SpanRangeExt;
use clippy_utils::{expr_or_init, path_def_id, paths, std_or_core};
use clippy_utils::{expr_or_init, is_path_diagnostic_item, std_or_core, sym};
use rustc_ast::LitKind;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, GenericArg, Mutability, QPath, Ty, TyKind};
@ -53,8 +53,7 @@ fn is_expr_const_aligned(cx: &LateContext<'_>, expr: &Expr<'_>, to: &Ty<'_>) ->
fn is_align_of_call(cx: &LateContext<'_>, fun: &Expr<'_>, to: &Ty<'_>) -> bool {
if let ExprKind::Path(QPath::Resolved(_, path)) = fun.kind
&& let Some(fun_id) = path_def_id(cx, fun)
&& paths::ALIGN_OF.matches(cx, fun_id)
&& is_path_diagnostic_item(cx, fun, sym::mem_align_of)
&& let Some(args) = path.segments.last().and_then(|seg| seg.args)
&& let [GenericArg::Type(generic_ty)] = args.args
{

View file

@ -185,7 +185,7 @@ pub(super) fn check<'tcx>(
Node::Expr(parent) if is_borrow_expr(cx, parent) && !is_in_allowed_macro(cx, parent) => {
MaybeParenOrBlock::Block
},
Node::Expr(parent) if cast_expr.precedence() < parent.precedence() => MaybeParenOrBlock::Paren,
Node::Expr(parent) if cx.precedence(cast_expr) < cx.precedence(parent) => MaybeParenOrBlock::Paren,
_ => MaybeParenOrBlock::Nothing,
};

View file

@ -42,7 +42,7 @@ declare_clippy_lint! {
/// ```
#[clippy::version = "1.88.0"]
pub COERCE_CONTAINER_TO_ANY,
suspicious,
nursery,
"coercing to `&dyn Any` when dereferencing could produce a `dyn Any` without coercion is usually not intended"
}
declare_lint_pass!(CoerceContainerToAny => [COERCE_CONTAINER_TO_ANY]);

View file

@ -972,7 +972,7 @@ fn report<'tcx>(
"&"
};
let expr_str = if !expr_is_macro_call && is_ufcs && expr.precedence() < ExprPrecedence::Prefix {
let expr_str = if !expr_is_macro_call && is_ufcs && cx.precedence(expr) < ExprPrecedence::Prefix {
Cow::Owned(format!("({expr_str})"))
} else {
expr_str
@ -1015,10 +1015,10 @@ fn report<'tcx>(
Node::Expr(e) => match e.kind {
ExprKind::Call(callee, _) if callee.hir_id != data.first_expr.hir_id => false,
ExprKind::Call(..) => {
expr.precedence() < ExprPrecedence::Unambiguous
cx.precedence(expr) < ExprPrecedence::Unambiguous
|| matches!(expr.kind, ExprKind::Field(..))
},
_ => expr.precedence() < e.precedence(),
_ => cx.precedence(expr) < cx.precedence(e),
},
_ => false,
};
@ -1066,7 +1066,7 @@ fn report<'tcx>(
Mutability::Not => "&",
Mutability::Mut => "&mut ",
};
(prefix, expr.precedence() < ExprPrecedence::Prefix)
(prefix, cx.precedence(expr) < ExprPrecedence::Prefix)
},
None if !ty.is_ref() && data.adjusted_ty.is_ref() => ("&", false),
_ => ("", false),
@ -1172,7 +1172,7 @@ impl<'tcx> Dereferencing<'tcx> {
},
Some(parent) if !parent.span.from_expansion() => {
// Double reference might be needed at this point.
if parent.precedence() == ExprPrecedence::Unambiguous {
if cx.precedence(parent) == ExprPrecedence::Unambiguous {
// Parentheses would be needed here, don't lint.
*outer_pat = None;
} else {

View file

@ -1,4 +1,5 @@
use clippy_utils::diagnostics::span_lint_and_then;
use rustc_ast::attr::AttributeExt as _;
use rustc_ast::token::CommentKind;
use rustc_errors::Applicability;
use rustc_hir::{AttrStyle, Attribute};
@ -43,13 +44,15 @@ pub fn check(cx: &LateContext<'_>, doc: &str, range: Range<usize>, fragments: &F
"looks like a footnote ref, but has no matching footnote",
|diag| {
if this_fragment.kind == DocFragmentKind::SugaredDoc {
let (doc_attr, (_, doc_attr_comment_kind)) = attrs
let (doc_attr, (_, doc_attr_comment_kind), attr_style) = attrs
.iter()
.filter(|attr| attr.span().overlaps(this_fragment.span))
.rev()
.find_map(|attr| Some((attr, attr.doc_str_and_comment_kind()?)))
.find_map(|attr| {
Some((attr, attr.doc_str_and_comment_kind()?, attr.doc_resolution_scope()?))
})
.unwrap();
let (to_add, terminator) = match (doc_attr_comment_kind, doc_attr.style()) {
let (to_add, terminator) = match (doc_attr_comment_kind, attr_style) {
(CommentKind::Line, AttrStyle::Outer) => ("\n///\n/// ", ""),
(CommentKind::Line, AttrStyle::Inner) => ("\n//!\n//! ", ""),
(CommentKind::Block, AttrStyle::Outer) => ("\n/** ", " */"),

View file

@ -42,9 +42,8 @@ pub fn check(
let mut test_attr_spans = vec![];
let filename = FileName::anon_source_code(&code);
let fallback_bundle =
rustc_errors::fallback_fluent_bundle(rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(), false);
let emitter = HumanEmitter::new(Box::new(io::sink()), fallback_bundle);
let translator = rustc_driver::default_translator();
let emitter = HumanEmitter::new(Box::new(io::sink()), translator);
let dcx = DiagCtxt::new(Box::new(emitter)).disable_warnings();
#[expect(clippy::arc_with_non_send_sync)] // `Arc` is expected by with_dcx
let sm = Arc::new(SourceMap::new(FilePathMapping::empty()));

View file

@ -7,6 +7,7 @@ use clippy_utils::{
get_path_from_caller_to_method_type, is_adjusted, is_no_std_crate, path_to_local, path_to_local_id,
};
use rustc_abi::ExternAbi;
use rustc_attr_data_structures::{AttributeKind, find_attr};
use rustc_errors::Applicability;
use rustc_hir::{BindingMode, Expr, ExprKind, FnRetTy, GenericArgs, Param, PatKind, QPath, Safety, TyKind};
use rustc_infer::infer::TyCtxtInferExt;
@ -161,7 +162,7 @@ fn check_closure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tcx
let sig = match callee_ty_adjusted.kind() {
ty::FnDef(def, _) => {
// Rewriting `x(|| f())` to `x(f)` where f is marked `#[track_caller]` moves the `Location`
if cx.tcx.has_attr(*def, sym::track_caller) {
if find_attr!(cx.tcx.get_all_attrs(*def), AttributeKind::TrackCaller(..)) {
return;
}
@ -249,7 +250,7 @@ fn check_closure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tcx
},
ExprKind::MethodCall(path, self_, args, _) if check_inputs(typeck, body.params, Some(self_), args) => {
if let Some(method_def_id) = typeck.type_dependent_def_id(body.value.hir_id)
&& !cx.tcx.has_attr(method_def_id, sym::track_caller)
&& !find_attr!(cx.tcx.get_all_attrs(method_def_id), AttributeKind::TrackCaller(..))
&& check_sig(closure_sig, cx.tcx.fn_sig(method_def_id).skip_binder().skip_binder())
{
let mut app = Applicability::MachineApplicable;

View file

@ -14,6 +14,8 @@ use clippy_utils::source::SpanRangeExt;
use clippy_utils::ty::is_must_use_ty;
use clippy_utils::visitors::for_each_expr_without_closures;
use clippy_utils::{return_ty, trait_ref_of_method};
use rustc_attr_data_structures::{AttributeKind, find_attr};
use rustc_span::Symbol;
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
use core::ops::ControlFlow;
@ -22,7 +24,7 @@ use super::{DOUBLE_MUST_USE, MUST_USE_CANDIDATE, MUST_USE_UNIT};
pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
let attrs = cx.tcx.hir_attrs(item.hir_id());
let attr = cx.tcx.get_attr(item.owner_id, sym::must_use);
let attr = find_attr!(cx.tcx.hir_attrs(item.hir_id()), AttributeKind::MustUse { span, reason } => (span, reason));
if let hir::ItemKind::Fn {
ref sig,
body: ref body_id,
@ -31,9 +33,19 @@ pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>
{
let is_public = cx.effective_visibilities.is_exported(item.owner_id.def_id);
let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
if let Some(attr) = attr {
check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr, attrs, sig);
} else if is_public && !is_proc_macro(attrs) && !attrs.iter().any(|a| a.has_name(sym::no_mangle)) {
if let Some((attr_span, reason)) = attr {
check_needless_must_use(
cx,
sig.decl,
item.owner_id,
item.span,
fn_header_span,
*attr_span,
*reason,
attrs,
sig,
);
} else if is_public && !is_proc_macro(attrs) && !find_attr!(attrs, AttributeKind::NoMangle(..)) {
check_must_use_candidate(
cx,
sig.decl,
@ -52,9 +64,20 @@ pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Imp
let is_public = cx.effective_visibilities.is_exported(item.owner_id.def_id);
let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
let attrs = cx.tcx.hir_attrs(item.hir_id());
let attr = cx.tcx.get_attr(item.owner_id, sym::must_use);
if let Some(attr) = attr {
check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr, attrs, sig);
let attr =
find_attr!(cx.tcx.hir_attrs(item.hir_id()), AttributeKind::MustUse { span, reason } => (span, reason));
if let Some((attr_span, reason)) = attr {
check_needless_must_use(
cx,
sig.decl,
item.owner_id,
item.span,
fn_header_span,
*attr_span,
*reason,
attrs,
sig,
);
} else if is_public && !is_proc_macro(attrs) && trait_ref_of_method(cx, item.owner_id).is_none() {
check_must_use_candidate(
cx,
@ -75,9 +98,20 @@ pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Tr
let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
let attrs = cx.tcx.hir_attrs(item.hir_id());
let attr = cx.tcx.get_attr(item.owner_id, sym::must_use);
if let Some(attr) = attr {
check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr, attrs, sig);
let attr =
find_attr!(cx.tcx.hir_attrs(item.hir_id()), AttributeKind::MustUse { span, reason } => (span, reason));
if let Some((attr_span, reason)) = attr {
check_needless_must_use(
cx,
sig.decl,
item.owner_id,
item.span,
fn_header_span,
*attr_span,
*reason,
attrs,
sig,
);
} else if let hir::TraitFn::Provided(eid) = *eid {
let body = cx.tcx.hir_body(eid);
if attr.is_none() && is_public && !is_proc_macro(attrs) {
@ -103,7 +137,8 @@ fn check_needless_must_use(
item_id: hir::OwnerId,
item_span: Span,
fn_header_span: Span,
attr: &Attribute,
attr_span: Span,
reason: Option<Symbol>,
attrs: &[Attribute],
sig: &FnSig<'_>,
) {
@ -118,12 +153,7 @@ fn check_needless_must_use(
fn_header_span,
"this unit-returning function has a `#[must_use]` attribute",
|diag| {
diag.span_suggestion(
attr.span(),
"remove the attribute",
"",
Applicability::MachineApplicable,
);
diag.span_suggestion(attr_span, "remove the attribute", "", Applicability::MachineApplicable);
},
);
} else {
@ -137,11 +167,11 @@ fn check_needless_must_use(
MUST_USE_UNIT,
fn_header_span,
"this unit-returning function has a `#[must_use]` attribute",
Some(attr.span()),
Some(attr_span),
"remove `must_use`",
);
}
} else if attr.value_str().is_none() && is_must_use_ty(cx, return_ty(cx, item_id)) {
} else if reason.is_none() && is_must_use_ty(cx, return_ty(cx, item_id)) {
// Ignore async functions unless Future::Output type is a must_use type
if sig.header.is_async() {
let infcx = cx.tcx.infer_ctxt().build(cx.typing_mode());

View file

@ -1,10 +1,10 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::sugg::DiagExt;
use rustc_attr_data_structures::{AttributeKind, find_attr};
use rustc_errors::Applicability;
use rustc_hir::{TraitFn, TraitItem, TraitItemKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::declare_lint_pass;
use rustc_span::sym;
declare_clippy_lint! {
/// ### What it does
@ -32,15 +32,19 @@ declare_lint_pass!(InlineFnWithoutBody => [INLINE_FN_WITHOUT_BODY]);
impl<'tcx> LateLintPass<'tcx> for InlineFnWithoutBody {
fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) {
if let TraitItemKind::Fn(_, TraitFn::Required(_)) = item.kind
&& let Some(attr) = cx.tcx.hir_attrs(item.hir_id()).iter().find(|a| a.has_name(sym::inline))
&& let Some(attr_span) = find_attr!(cx
.tcx
.hir_attrs(item.hir_id()),
AttributeKind::Inline(_, span) => *span
)
{
span_lint_and_then(
cx,
INLINE_FN_WITHOUT_BODY,
attr.span(),
attr_span,
format!("use of `#[inline]` on trait method `{}` which has no body", item.ident),
|diag| {
diag.suggest_remove_item(cx, attr.span(), "remove", Applicability::MachineApplicable);
diag.suggest_remove_item(cx, attr_span, "remove", Applicability::MachineApplicable);
},
);
}

View file

@ -84,7 +84,7 @@ pub(super) fn check<'tcx>(
if !prefix.is_empty()
&& (
// Precedence of internal expression is less than or equal to precedence of `&expr`.
arg_expression.precedence() <= ExprPrecedence::Prefix || is_range_literal(arg_expression)
cx.precedence(arg_expression) <= ExprPrecedence::Prefix || is_range_literal(arg_expression)
)
{
arg_snip = format!("({arg_snip})").into();

View file

@ -1,7 +1,7 @@
use clippy_config::Conf;
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
use clippy_utils::msrvs::Msrv;
use clippy_utils::{is_none_arm, msrvs, paths, peel_hir_expr_refs, sym};
use clippy_utils::{is_none_arm, msrvs, peel_hir_expr_refs, sym};
use rustc_errors::Applicability;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::{Arm, Expr, ExprKind, LangItem, Pat, PatKind, QPath, is_range_literal};
@ -220,5 +220,5 @@ fn is_empty_slice(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
}
fn is_slice_from_ref(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
paths::SLICE_FROM_REF.matches_path(cx, expr)
clippy_utils::is_path_diagnostic_item(cx, expr, sym::slice_from_ref)
}

View file

@ -117,7 +117,7 @@ where
// it's being passed by value.
let scrutinee = peel_hir_expr_refs(scrutinee).0;
let (scrutinee_str, _) = snippet_with_context(cx, scrutinee.span, expr_ctxt, "..", &mut app);
let scrutinee_str = if scrutinee.span.eq_ctxt(expr.span) && scrutinee.precedence() < ExprPrecedence::Unambiguous {
let scrutinee_str = if scrutinee.span.eq_ctxt(expr.span) && cx.precedence(scrutinee) < ExprPrecedence::Unambiguous {
format!("({scrutinee_str})")
} else {
scrutinee_str.into()

View file

@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::{expr_or_init, paths};
use clippy_utils::{expr_or_init, is_path_diagnostic_item, sym};
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, QPath};
use rustc_lint::LateContext;
@ -10,8 +10,11 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, path: &Expr<'_>, args
&& !expr.span.from_expansion()
&& !error_kind.span.from_expansion()
&& let ExprKind::Path(QPath::TypeRelative(_, new_segment)) = path.kind
&& paths::IO_ERROR_NEW.matches_path(cx, path)
&& paths::IO_ERRORKIND_OTHER_CTOR.matches_path(cx, expr_or_init(cx, error_kind))
&& is_path_diagnostic_item(cx, path, sym::io_error_new)
&& let ExprKind::Path(QPath::Resolved(_, init_path)) = &expr_or_init(cx, error_kind).kind
&& let [.., error_kind_ty, error_kind_variant] = init_path.segments
&& cx.tcx.is_diagnostic_item(sym::io_errorkind, error_kind_ty.res.def_id())
&& error_kind_variant.ident.name == sym::Other
&& msrv.meets(cx, msrvs::IO_ERROR_OTHER)
{
span_lint_and_then(

View file

@ -388,9 +388,11 @@ fn check_other_call_arg<'tcx>(
&& let (input, n_refs) = peel_middle_ty_refs(*input)
&& let (trait_predicates, _) = get_input_traits_and_projections(cx, callee_def_id, input)
&& let Some(sized_def_id) = cx.tcx.lang_items().sized_trait()
&& let Some(meta_sized_def_id) = cx.tcx.lang_items().meta_sized_trait()
&& let [trait_predicate] = trait_predicates
.iter()
.filter(|trait_predicate| trait_predicate.def_id() != sized_def_id)
.filter(|trait_predicate| trait_predicate.def_id() != meta_sized_def_id)
.collect::<Vec<_>>()[..]
&& let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref)
&& let Some(as_ref_trait_id) = cx.tcx.get_diagnostic_item(sym::AsRef)

View file

@ -1,10 +1,11 @@
use clippy_utils::diagnostics::span_lint;
use rustc_attr_data_structures::{AttributeKind, find_attr};
use rustc_hir as hir;
use rustc_hir::Attribute;
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::ty::AssocItemContainer;
use rustc_session::declare_lint_pass;
use rustc_span::{Span, sym};
use rustc_span::Span;
declare_clippy_lint! {
/// ### What it does
@ -64,8 +65,7 @@ declare_clippy_lint! {
}
fn check_missing_inline_attrs(cx: &LateContext<'_>, attrs: &[Attribute], sp: Span, desc: &'static str) {
let has_inline = attrs.iter().any(|a| a.has_name(sym::inline));
if !has_inline {
if !find_attr!(attrs, AttributeKind::Inline(..)) {
span_lint(
cx,
MISSING_INLINE_IN_PUBLIC_ITEMS,

View file

@ -161,7 +161,7 @@ fn path_has_args(p: &QPath<'_>) -> bool {
/// - `Copy` itself, or
/// - the only use of a mutable reference, or
/// - not a variable (created by a function call)
#[expect(clippy::too_many_arguments)]
#[expect(clippy::too_many_arguments, clippy::too_many_lines)]
fn needless_borrow_count<'tcx>(
cx: &LateContext<'tcx>,
possible_borrowers: &mut Vec<(LocalDefId, PossibleBorrowerMap<'tcx, 'tcx>)>,
@ -174,6 +174,7 @@ fn needless_borrow_count<'tcx>(
) -> usize {
let destruct_trait_def_id = cx.tcx.lang_items().destruct_trait();
let sized_trait_def_id = cx.tcx.lang_items().sized_trait();
let meta_sized_trait_def_id = cx.tcx.lang_items().meta_sized_trait();
let drop_trait_def_id = cx.tcx.lang_items().drop_trait();
let fn_sig = cx.tcx.fn_sig(fn_id).instantiate_identity().skip_binder();
@ -209,6 +210,7 @@ fn needless_borrow_count<'tcx>(
.all(|trait_def_id| {
Some(trait_def_id) == destruct_trait_def_id
|| Some(trait_def_id) == sized_trait_def_id
|| Some(trait_def_id) == meta_sized_trait_def_id
|| cx.tcx.is_diagnostic_item(sym::Any, trait_def_id)
})
{
@ -230,11 +232,11 @@ fn needless_borrow_count<'tcx>(
let mut args_with_referent_ty = callee_args.to_vec();
let mut check_reference_and_referent = |reference: &Expr<'tcx>, referent: &Expr<'tcx>| {
if let ExprKind::Field(base, _) = &referent.kind {
let base_ty = cx.typeck_results().expr_ty(base);
if drop_trait_def_id.is_some_and(|id| implements_trait(cx, base_ty, id, &[])) {
return false;
}
if let ExprKind::Field(base, _) = &referent.kind
&& let base_ty = cx.typeck_results().expr_ty(base)
&& drop_trait_def_id.is_some_and(|id| implements_trait(cx, base_ty, id, &[]))
{
return false;
}
let referent_ty = cx.typeck_results().expr_ty(referent);

View file

@ -116,13 +116,18 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
];
let sized_trait = need!(cx.tcx.lang_items().sized_trait());
let meta_sized_trait = need!(cx.tcx.lang_items().meta_sized_trait());
let preds = traits::elaborate(cx.tcx, cx.param_env.caller_bounds().iter())
.filter(|p| !p.is_global())
.filter_map(|pred| {
// Note that we do not want to deal with qualified predicates here.
match pred.kind().no_bound_vars() {
Some(ty::ClauseKind::Trait(pred)) if pred.def_id() != sized_trait => Some(pred),
Some(ty::ClauseKind::Trait(pred))
if pred.def_id() != sized_trait && pred.def_id() != meta_sized_trait =>
{
Some(pred)
},
_ => None,
}
})

View file

@ -64,7 +64,7 @@ fn check_mul(cx: &LateContext<'_>, span: Span, lit: &Expr<'_>, exp: &Expr<'_>) {
{
let mut applicability = Applicability::MachineApplicable;
let (snip, from_macro) = snippet_with_context(cx, exp.span, span.ctxt(), "..", &mut applicability);
let suggestion = if !from_macro && exp.precedence() < ExprPrecedence::Prefix && !has_enclosing_paren(&snip) {
let suggestion = if !from_macro && cx.precedence(exp) < ExprPrecedence::Prefix && !has_enclosing_paren(&snip) {
format!("-({snip})")
} else {
format!("-{snip}")

View file

@ -1,8 +1,9 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::{snippet, snippet_with_applicability};
use rustc_abi::ExternAbi;
use rustc_attr_data_structures::AttributeKind;
use rustc_errors::Applicability;
use rustc_hir::{Item, ItemKind};
use rustc_hir::{Attribute, Item, ItemKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::declare_lint_pass;
use rustc_span::{BytePos, Pos};
@ -44,8 +45,7 @@ impl<'tcx> LateLintPass<'tcx> for NoMangleWithRustAbi {
let mut app = Applicability::MaybeIncorrect;
let fn_snippet = snippet_with_applicability(cx, fn_sig.span.with_hi(ident.span.lo()), "..", &mut app);
for attr in attrs {
if let Some(ident) = attr.ident()
&& ident.name == rustc_span::sym::no_mangle
if let Attribute::Parsed(AttributeKind::NoMangle(attr_span)) = attr
&& fn_sig.header.abi == ExternAbi::Rust
&& let Some((fn_attrs, _)) = fn_snippet.rsplit_once("fn")
&& !fn_attrs.contains("extern")
@ -54,7 +54,7 @@ impl<'tcx> LateLintPass<'tcx> for NoMangleWithRustAbi {
.span
.with_lo(fn_sig.span.lo() + BytePos::from_usize(fn_attrs.len()))
.shrink_to_lo();
let attr_snippet = snippet(cx, attr.span(), "..");
let attr_snippet = snippet(cx, *attr_span, "..");
span_lint_and_then(
cx,

View file

@ -5,7 +5,7 @@ use clippy_utils::ty::{for_each_top_level_late_bound_region, is_copy};
use clippy_utils::{is_self, is_self_ty};
use core::ops::ControlFlow;
use rustc_abi::ExternAbi;
use rustc_ast::attr;
use rustc_attr_data_structures::{AttributeKind, InlineAttr, find_attr};
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability;
use rustc_hir as hir;
@ -270,11 +270,13 @@ impl<'tcx> LateLintPass<'tcx> for PassByRefOrValue {
return;
}
let attrs = cx.tcx.hir_attrs(hir_id);
if find_attr!(attrs, AttributeKind::Inline(InlineAttr::Always, _)) {
return;
}
for a in attrs {
if let Some(meta_items) = a.meta_item_list()
&& (a.has_name(sym::proc_macro_derive)
|| (a.has_name(sym::inline) && attr::list_contains_name(&meta_items, sym::always)))
{
// FIXME(jdonszelmann): make part of the find_attr above
if a.has_name(sym::proc_macro_derive) {
return;
}
}

View file

@ -86,7 +86,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantSlicing {
let (indexed_ty, indexed_ref_count) = peel_middle_ty_refs(cx.typeck_results().expr_ty(indexed));
let parent_expr = get_parent_expr(cx, expr);
let needs_parens_for_prefix =
parent_expr.is_some_and(|parent| parent.precedence() > ExprPrecedence::Prefix);
parent_expr.is_some_and(|parent| cx.precedence(parent) > ExprPrecedence::Prefix);
if expr_ty == indexed_ty {
if expr_ref_count > indexed_ref_count {

View file

@ -1,12 +1,13 @@
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::ty::is_must_use_ty;
use clippy_utils::{nth_arg, return_ty};
use rustc_attr_data_structures::{AttributeKind, find_attr};
use rustc_hir::def_id::LocalDefId;
use rustc_hir::intravisit::FnKind;
use rustc_hir::{Body, FnDecl, OwnerId, TraitItem, TraitItemKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_session::declare_lint_pass;
use rustc_span::{Span, sym};
use rustc_span::Span;
declare_clippy_lint! {
/// ### What it does
@ -74,7 +75,10 @@ fn check_method(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_def: LocalDefId, spa
// We only show this warning for public exported methods.
&& cx.effective_visibilities.is_exported(fn_def)
// We don't want to emit this lint if the `#[must_use]` attribute is already there.
&& !cx.tcx.hir_attrs(owner_id.into()).iter().any(|attr| attr.has_name(sym::must_use))
&& !find_attr!(
cx.tcx.hir_attrs(owner_id.into()),
AttributeKind::MustUse { .. }
)
&& cx.tcx.visibility(fn_def.to_def_id()).is_public()
&& let ret_ty = return_ty(cx, owner_id)
&& let self_arg = nth_arg(cx, owner_id, 0)

View file

@ -3,7 +3,7 @@ use clippy_utils::higher::VecArgs;
use clippy_utils::macros::root_macro_call_first_node;
use clippy_utils::source::SpanRangeExt;
use clippy_utils::ty::implements_trait;
use clippy_utils::{is_no_std_crate, paths};
use clippy_utils::{is_no_std_crate, sym};
use rustc_ast::{LitIntType, LitKind, UintTy};
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, LangItem, QPath, StructTailExpr};
@ -100,7 +100,7 @@ impl LateLintPass<'_> for SingleRangeInVecInit {
&& let Some(start_snippet) = start.span.get_source_text(cx)
&& let Some(end_snippet) = end.span.get_source_text(cx)
{
let should_emit_every_value = if let Some(step_def_id) = paths::ITER_STEP.only(cx)
let should_emit_every_value = if let Some(step_def_id) = cx.tcx.get_diagnostic_item(sym::range_step)
&& implements_trait(cx, ty, step_def_id, &[])
{
true

View file

@ -2,7 +2,7 @@ use clippy_config::Conf;
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::{is_in_const_context, paths, sym};
use clippy_utils::{is_in_const_context, is_path_diagnostic_item, sym};
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass};
@ -62,7 +62,7 @@ impl<'tcx> LateLintPass<'tcx> for ToDigitIsSome {
}
},
hir::ExprKind::Call(to_digits_call, [char_arg, radix_arg]) => {
if paths::CHAR_TO_DIGIT.matches_path(cx, to_digits_call) {
if is_path_diagnostic_item(cx, to_digits_call, sym::char_to_digit) {
Some((false, char_arg, radix_arg))
} else {
None

View file

@ -44,7 +44,7 @@ pub(super) fn check<'tcx>(
};
if let Node::Expr(parent) = cx.tcx.parent_hir_node(e.hir_id)
&& parent.precedence() > ExprPrecedence::Cast
&& cx.precedence(parent) > ExprPrecedence::Cast
{
sugg = format!("({sugg})");
}

View file

@ -128,7 +128,7 @@ fn remove_all_parens(pat: &mut P<Pat>) {
}
impl MutVisitor for Visitor {
fn visit_pat(&mut self, pat: &mut P<Pat>) {
fn visit_pat(&mut self, pat: &mut Pat) {
let is_inner = mem::replace(&mut self.is_inner, true);
walk_pat(self, pat);
let inner = match &mut pat.kind {
@ -145,7 +145,7 @@ fn remove_all_parens(pat: &mut P<Pat>) {
fn insert_necessary_parens(pat: &mut P<Pat>) {
struct Visitor;
impl MutVisitor for Visitor {
fn visit_pat(&mut self, pat: &mut P<Pat>) {
fn visit_pat(&mut self, pat: &mut Pat) {
use ast::BindingMode;
walk_pat(self, pat);
let target = match &mut pat.kind {
@ -167,7 +167,7 @@ fn unnest_or_patterns(pat: &mut P<Pat>) -> bool {
changed: bool,
}
impl MutVisitor for Visitor {
fn visit_pat(&mut self, p: &mut P<Pat>) {
fn visit_pat(&mut self, p: &mut Pat) {
// This is a bottom up transformation, so recurse first.
walk_pat(self, p);

View file

@ -1,8 +1,7 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::macros::macro_backtrace;
use clippy_utils::paths::CONCAT;
use clippy_utils::source::snippet_opt;
use clippy_utils::tokenize_with_text;
use clippy_utils::{sym, tokenize_with_text};
use rustc_ast::LitKind;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind};
@ -43,7 +42,7 @@ impl LateLintPass<'_> for UselessConcat {
// Get the direct parent of the expression.
&& let Some(macro_call) = macro_backtrace(expr.span).next()
// Check if the `concat` macro from the `core` library.
&& CONCAT.matches(cx, macro_call.def_id)
&& cx.tcx.is_diagnostic_item(sym::macro_concat, macro_call.def_id)
// We get the original code to parse it.
&& let Some(original_code) = snippet_opt(cx, macro_call.span)
// This check allows us to ensure that the code snippet:

View file

@ -1,6 +1,6 @@
[package]
name = "clippy_utils"
version = "0.1.89"
version = "0.1.90"
edition = "2024"
description = "Helpful tools for writing lints, provided as they are used in Clippy"
repository = "https://github.com/rust-lang/rust-clippy"

View file

@ -8,7 +8,7 @@ This crate is only guaranteed to build with this `nightly` toolchain:
<!-- begin autogenerated nightly -->
```
nightly-2025-06-12
nightly-2025-06-26
```
<!-- end autogenerated nightly -->

View file

@ -1886,7 +1886,7 @@ pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
_ => None,
};
did.is_some_and(|did| cx.tcx.has_attr(did, sym::must_use))
did.is_some_and(|did| find_attr!(cx.tcx.get_all_attrs(did), AttributeKind::MustUse { .. }))
}
/// Checks if a function's body represents the identity function. Looks for bodies of the form:

View file

@ -126,15 +126,6 @@ path_macros! {
macro_path: PathNS::Macro,
}
// Paths in `core`/`alloc`/`std`. This should be avoided and cleaned up by adding diagnostic items.
pub static ALIGN_OF: PathLookup = value_path!(core::mem::align_of);
pub static CHAR_TO_DIGIT: PathLookup = value_path!(char::to_digit);
pub static CONCAT: PathLookup = macro_path!(core::concat);
pub static IO_ERROR_NEW: PathLookup = value_path!(std::io::Error::new);
pub static IO_ERRORKIND_OTHER_CTOR: PathLookup = value_path!(std::io::ErrorKind::Other);
pub static ITER_STEP: PathLookup = type_path!(core::iter::Step);
pub static SLICE_FROM_REF: PathLookup = value_path!(core::slice::from_ref);
// Paths in external crates
pub static FUTURES_IO_ASYNCREADEXT: PathLookup = type_path!(futures_util::AsyncReadExt);
pub static FUTURES_IO_ASYNCWRITEEXT: PathLookup = type_path!(futures_util::AsyncWriteExt);

View file

@ -34,10 +34,12 @@ pub fn is_min_const_fn<'tcx>(cx: &LateContext<'tcx>, body: &Body<'tcx>, msrv: Ms
}
if !msrv.meets(cx, msrvs::CONST_FN_TRAIT_BOUND)
&& let Some(sized_did) = cx.tcx.lang_items().sized_trait()
&& let Some(meta_sized_did) = cx.tcx.lang_items().meta_sized_trait()
&& cx.tcx.param_env(def_id).caller_bounds().iter().any(|bound| {
bound
.as_trait_clause()
.is_some_and(|clause| clause.def_id() != sized_did)
bound.as_trait_clause().is_some_and(|clause| {
let did = clause.def_id();
did != sized_did && did != meta_sized_did
})
})
{
return Err((

View file

@ -46,7 +46,6 @@ generate! {
DOUBLE_QUOTE: "\"",
Deserialize,
EarlyLintPass,
ErrorKind,
IntoIter,
Itertools,
LF: "\n",
@ -65,7 +64,6 @@ generate! {
RegexBuilder,
RegexSet,
Start,
Step,
Symbol,
SyntaxContext,
TBD,
@ -76,7 +74,6 @@ generate! {
Visitor,
Weak,
abs,
align_of,
ambiguous_glob_reexports,
append,
arg,
@ -159,7 +156,6 @@ generate! {
from_ne_bytes,
from_ptr,
from_raw,
from_ref,
from_str,
from_str_radix,
fs,
@ -218,7 +214,6 @@ generate! {
max_by_key,
max_value,
maximum,
mem,
min,
min_by,
min_by_key,

View file

@ -6,6 +6,7 @@ use core::ops::ControlFlow;
use itertools::Itertools;
use rustc_abi::VariantIdx;
use rustc_ast::ast::Mutability;
use rustc_attr_data_structures::{AttributeKind, find_attr};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
@ -20,8 +21,8 @@ use rustc_middle::traits::EvaluationResult;
use rustc_middle::ty::layout::ValidityRequirement;
use rustc_middle::ty::{
self, AdtDef, AliasTy, AssocItem, AssocTag, Binder, BoundRegion, FnSig, GenericArg, GenericArgKind, GenericArgsRef,
GenericParamDefKind, IntTy, Region, RegionKind, TraitRef, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable,
TypeVisitable, TypeVisitableExt, TypeVisitor, UintTy, Upcast, VariantDef, VariantDiscr,
GenericParamDefKind, IntTy, Region, RegionKind, TraitRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
TypeVisitableExt, TypeVisitor, UintTy, Upcast, VariantDef, VariantDiscr,
};
use rustc_span::symbol::Ident;
use rustc_span::{DUMMY_SP, Span, Symbol, sym};
@ -326,8 +327,8 @@ pub fn has_drop<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
// Returns whether the type has #[must_use] attribute
pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
match ty.kind() {
ty::Adt(adt, _) => cx.tcx.has_attr(adt.did(), sym::must_use),
ty::Foreign(did) => cx.tcx.has_attr(*did, sym::must_use),
ty::Adt(adt, _) => find_attr!(cx.tcx.get_all_attrs(adt.did()), AttributeKind::MustUse { .. }),
ty::Foreign(did) => find_attr!(cx.tcx.get_all_attrs(*did), AttributeKind::MustUse { .. }),
ty::Slice(ty) | ty::Array(ty, _) | ty::RawPtr(ty, _) | ty::Ref(_, ty, _) => {
// for the Array case we don't need to care for the len == 0 case
// because we don't want to lint functions returning empty arrays
@ -337,7 +338,10 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
ty::Alias(ty::Opaque, AliasTy { def_id, .. }) => {
for (predicate, _) in cx.tcx.explicit_item_self_bounds(def_id).skip_binder() {
if let ty::ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder()
&& cx.tcx.has_attr(trait_predicate.trait_ref.def_id, sym::must_use)
&& find_attr!(
cx.tcx.get_all_attrs(trait_predicate.trait_ref.def_id),
AttributeKind::MustUse { .. }
)
{
return true;
}
@ -347,7 +351,7 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
ty::Dynamic(binder, _, _) => {
for predicate in *binder {
if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder()
&& cx.tcx.has_attr(trait_ref.def_id, sym::must_use)
&& find_attr!(cx.tcx.get_all_attrs(trait_ref.def_id), AttributeKind::MustUse { .. })
{
return true;
}
@ -853,7 +857,7 @@ pub fn for_each_top_level_late_bound_region<B>(
ControlFlow::Continue(())
}
}
fn visit_binder<T: TypeFoldable<TyCtxt<'tcx>>>(&mut self, t: &Binder<'tcx, T>) -> Self::Result {
fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(&mut self, t: &Binder<'tcx, T>) -> Self::Result {
self.index += 1;
let res = t.super_visit_with(self);
self.index -= 1;

View file

@ -1,6 +1,6 @@
[package]
name = "declare_clippy_lint"
version = "0.1.89"
version = "0.1.90"
edition = "2024"
repository = "https://github.com/rust-lang/rust-clippy"
license = "MIT OR Apache-2.0"

View file

@ -1,6 +1,6 @@
[toolchain]
# begin autogenerated nightly
channel = "nightly-2025-06-12"
channel = "nightly-2025-06-26"
# end autogenerated nightly
components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
profile = "minimal"

View file

@ -13,6 +13,11 @@ extern crate rustc_interface;
extern crate rustc_session;
extern crate rustc_span;
// See docs in https://github.com/rust-lang/rust/blob/master/compiler/rustc/src/main.rs
// about jemalloc.
#[cfg(feature = "jemalloc")]
extern crate tikv_jemalloc_sys as jemalloc_sys;
use clippy_utils::sym;
use declare_clippy_lint::LintListBuilder;
use rustc_interface::interface;
@ -187,6 +192,36 @@ const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust-clippy/issues/ne
#[allow(clippy::too_many_lines)]
#[allow(clippy::ignored_unit_patterns)]
pub fn main() {
// See docs in https://github.com/rust-lang/rust/blob/master/compiler/rustc/src/main.rs
// about jemalloc.
#[cfg(feature = "jemalloc")]
{
use std::os::raw::{c_int, c_void};
#[used]
static _F1: unsafe extern "C" fn(usize, usize) -> *mut c_void = jemalloc_sys::calloc;
#[used]
static _F2: unsafe extern "C" fn(*mut *mut c_void, usize, usize) -> c_int = jemalloc_sys::posix_memalign;
#[used]
static _F3: unsafe extern "C" fn(usize, usize) -> *mut c_void = jemalloc_sys::aligned_alloc;
#[used]
static _F4: unsafe extern "C" fn(usize) -> *mut c_void = jemalloc_sys::malloc;
#[used]
static _F5: unsafe extern "C" fn(*mut c_void, usize) -> *mut c_void = jemalloc_sys::realloc;
#[used]
static _F6: unsafe extern "C" fn(*mut c_void) = jemalloc_sys::free;
#[cfg(target_os = "macos")]
{
unsafe extern "C" {
fn _rjem_je_zone_register();
}
#[used]
static _F7: unsafe extern "C" fn() = _rjem_je_zone_register;
}
}
let early_dcx = EarlyDiagCtxt::new(ErrorOutputType::default());
rustc_driver::init_rustc_env_logger(&early_dcx);

View file

@ -9,28 +9,35 @@ if let StmtKind::Let(local) = stmt.kind
&& let ExprKind::Call(func, args) = e.kind
&& paths::STD_IO_STDIO__PRINT.matches_path(cx, func) // Add the path to `clippy_utils::paths` if needed
&& args.len() == 1
&& let ExprKind::Call(func1, args1) = args[0].kind
&& paths::CORE_FMT_RT_NEW_V1.matches_path(cx, func1) // Add the path to `clippy_utils::paths` if needed
&& args1.len() == 2
&& let ExprKind::Block(block1, None) = args[0].kind
&& block1.stmts.len() == 1
&& let StmtKind::Let(local1) = block1.stmts[0].kind
&& let Some(init1) = local1.init
&& let ExprKind::Array(elements) = init1.kind
&& elements.len() == 1
&& let ExprKind::Call(func1, args1) = elements[0].kind
&& paths::CORE_FMT_RT_ARGUMENT_NEW_DISPLAY.matches_path(cx, func1) // Add the path to `clippy_utils::paths` if needed
&& args1.len() == 1
&& let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = args1[0].kind
&& let ExprKind::Array(elements) = inner.kind
&& elements.len() == 2
&& let ExprKind::Lit(ref lit) = elements[0].kind
&& let PatKind::Binding(BindingMode::NONE, _, name, None) = local1.pat.kind
&& name.as_str() == "args"
&& let Some(trailing_expr) = block1.expr
&& let ExprKind::Call(func2, args2) = trailing_expr.kind
&& paths::CORE_FMT_RT_NEW_V1.matches_path(cx, func2) // Add the path to `clippy_utils::paths` if needed
&& args2.len() == 2
&& let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner1) = args2[0].kind
&& let ExprKind::Array(elements1) = inner1.kind
&& elements1.len() == 2
&& let ExprKind::Lit(ref lit) = elements1[0].kind
&& let LitKind::Str(s, _) = lit.node
&& s.as_str() == ""
&& let ExprKind::Lit(ref lit1) = elements[1].kind
&& let ExprKind::Lit(ref lit1) = elements1[1].kind
&& let LitKind::Str(s1, _) = lit1.node
&& s1.as_str() == "\n"
&& let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner1) = args1[1].kind
&& let ExprKind::Array(elements1) = inner1.kind
&& elements1.len() == 1
&& let ExprKind::Call(func2, args2) = elements1[0].kind
&& paths::CORE_FMT_RT_ARGUMENT_NEW_DISPLAY.matches_path(cx, func2) // Add the path to `clippy_utils::paths` if needed
&& args2.len() == 1
&& let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner2) = args2[0].kind
&& let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner2) = args2[1].kind
&& block.expr.is_none()
&& let PatKind::Binding(BindingMode::NONE, _, name, None) = local.pat.kind
&& name.as_str() == "print_text"
&& let PatKind::Binding(BindingMode::NONE, _, name1, None) = local.pat.kind
&& name1.as_str() == "print_text"
{
// report your lint here
}

View file

@ -19,25 +19,32 @@ if let Some(higher::ForLoop { pat: pat, arg: arg, body: body, .. }) = higher::Fo
&& let ExprKind::Call(func, args) = e1.kind
&& paths::STD_IO_STDIO__PRINT.matches_path(cx, func) // Add the path to `clippy_utils::paths` if needed
&& args.len() == 1
&& let ExprKind::Call(func1, args1) = args[0].kind
&& paths::CORE_FMT_RT_NEW_V1.matches_path(cx, func1) // Add the path to `clippy_utils::paths` if needed
&& args1.len() == 2
&& let ExprKind::Block(block2, None) = args[0].kind
&& block2.stmts.len() == 1
&& let StmtKind::Let(local) = block2.stmts[0].kind
&& let Some(init) = local.init
&& let ExprKind::Array(elements) = init.kind
&& elements.len() == 1
&& let ExprKind::Call(func1, args1) = elements[0].kind
&& paths::CORE_FMT_RT_ARGUMENT_NEW_DISPLAY.matches_path(cx, func1) // Add the path to `clippy_utils::paths` if needed
&& args1.len() == 1
&& let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = args1[0].kind
&& let ExprKind::Array(elements) = inner.kind
&& elements.len() == 2
&& let ExprKind::Lit(ref lit2) = elements[0].kind
&& let PatKind::Binding(BindingMode::NONE, _, name1, None) = local.pat.kind
&& name1.as_str() == "args"
&& let Some(trailing_expr) = block2.expr
&& let ExprKind::Call(func2, args2) = trailing_expr.kind
&& paths::CORE_FMT_RT_NEW_V1.matches_path(cx, func2) // Add the path to `clippy_utils::paths` if needed
&& args2.len() == 2
&& let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner1) = args2[0].kind
&& let ExprKind::Array(elements1) = inner1.kind
&& elements1.len() == 2
&& let ExprKind::Lit(ref lit2) = elements1[0].kind
&& let LitKind::Str(s, _) = lit2.node
&& s.as_str() == ""
&& let ExprKind::Lit(ref lit3) = elements[1].kind
&& let ExprKind::Lit(ref lit3) = elements1[1].kind
&& let LitKind::Str(s1, _) = lit3.node
&& s1.as_str() == "\n"
&& let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner1) = args1[1].kind
&& let ExprKind::Array(elements1) = inner1.kind
&& elements1.len() == 1
&& let ExprKind::Call(func2, args2) = elements1[0].kind
&& paths::CORE_FMT_RT_ARGUMENT_NEW_DISPLAY.matches_path(cx, func2) // Add the path to `clippy_utils::paths` if needed
&& args2.len() == 1
&& let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner2) = args2[0].kind
&& let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner2) = args2[1].kind
&& block1.expr.is_none()
&& block.expr.is_none()
{

View file

@ -7,8 +7,14 @@
#[link(name = "c")]
unsafe extern "C" {}
#[lang = "pointee_sized"]
pub trait PointeeSized {}
#[lang = "meta_sized"]
pub trait MetaSized: PointeeSized {}
#[lang = "sized"]
pub trait Sized {}
pub trait Sized: MetaSized {}
#[lang = "copy"]
pub trait Copy {}
#[lang = "freeze"]

View file

@ -1,5 +1,5 @@
error: methods called `as_*` usually take `self` by reference or `self` by mutable reference
--> tests/ui/def_id_nocore.rs:27:19
--> tests/ui/def_id_nocore.rs:33:19
|
LL | pub fn as_ref(self) -> &'static str {
| ^^^^

View file

@ -1,8 +1,7 @@
//@ normalize-stderr-test: "\b10000(08|16|32)\b" -> "100$$PTR"
//@ normalize-stderr-test: "\b2500(060|120)\b" -> "250$$PTR"
#![allow(unused, incomplete_features)]
#![allow(unused)]
#![warn(clippy::large_stack_frames)]
#![feature(unsized_locals)]
use std::hint::black_box;
@ -11,11 +10,6 @@ fn generic<T: Default>() {
black_box(&x);
}
fn unsized_local() {
let x: dyn std::fmt::Display = *(Box::new(1) as Box<dyn std::fmt::Display>);
black_box(&x);
}
struct ArrayDefault<const N: usize>([u8; N]);
impl<const N: usize> Default for ArrayDefault<N> {

View file

@ -1,5 +1,5 @@
error: this function may allocate 250$PTR bytes on the stack
--> tests/ui/large_stack_frames.rs:27:4
--> tests/ui/large_stack_frames.rs:21:4
|
LL | fn many_small_arrays() {
| ^^^^^^^^^^^^^^^^^
@ -13,7 +13,7 @@ LL | let x5 = [0u8; 500_000];
= help: to override `-D warnings` add `#[allow(clippy::large_stack_frames)]`
error: this function may allocate 1000000 bytes on the stack
--> tests/ui/large_stack_frames.rs:38:4
--> tests/ui/large_stack_frames.rs:32:4
|
LL | fn large_return_value() -> ArrayDefault<1_000_000> {
| ^^^^^^^^^^^^^^^^^^ ----------------------- this is the largest part, at 1000000 bytes for type `ArrayDefault<1000000>`
@ -21,7 +21,7 @@ LL | fn large_return_value() -> ArrayDefault<1_000_000> {
= note: 1000000 bytes is larger than Clippy's configured `stack-size-threshold` of 512000
error: this function may allocate 100$PTR bytes on the stack
--> tests/ui/large_stack_frames.rs:44:4
--> tests/ui/large_stack_frames.rs:38:4
|
LL | fn large_fn_arg(x: ArrayDefault<1_000_000>) {
| ^^^^^^^^^^^^ - `x` is the largest part, at 1000000 bytes for type `ArrayDefault<1000000>`
@ -29,7 +29,7 @@ LL | fn large_fn_arg(x: ArrayDefault<1_000_000>) {
= note: 100$PTR bytes is larger than Clippy's configured `stack-size-threshold` of 512000
error: this function may allocate 100$PTR bytes on the stack
--> tests/ui/large_stack_frames.rs:51:13
--> tests/ui/large_stack_frames.rs:45:13
|
LL | let f = || black_box(&[0u8; 1_000_000]);
| ^^^^^^^^^^^^^^----------------^

View file

@ -154,7 +154,6 @@ fn main() {
});
let _ = [0]
//~^ suspicious_map
.into_iter()
.inspect(|&x| {
//~^ manual_inspect

View file

@ -165,7 +165,6 @@ fn main() {
});
let _ = [0]
//~^ suspicious_map
.into_iter()
.map(|x| {
//~^ manual_inspect

View file

@ -157,25 +157,8 @@ LL |
LL ~ println!("{}", x);
|
error: this call to `map()` won't have an effect on the call to `count()`
--> tests/ui/manual_inspect.rs:167:13
|
LL | let _ = [0]
| _____________^
LL | |
LL | | .into_iter()
LL | | .map(|x| {
... |
LL | | })
LL | | .count();
| |________________^
|
= help: make sure you did not confuse `map` with `filter`, `for_each` or `inspect`
= note: `-D clippy::suspicious-map` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::suspicious_map)]`
error: using `map` over `inspect`
--> tests/ui/manual_inspect.rs:170:10
--> tests/ui/manual_inspect.rs:169:10
|
LL | .map(|x| {
| ^^^
@ -188,7 +171,7 @@ LL ~ println!("{}", x);
|
error: using `map` over `inspect`
--> tests/ui/manual_inspect.rs:203:30
--> tests/ui/manual_inspect.rs:202:30
|
LL | if let Some(x) = Some(1).map(|x| { println!("{x}");
| ^^^
@ -200,5 +183,5 @@ LL | // Do not collapse code into this comment
LL ~ }) {
|
error: aborting due to 14 previous errors
error: aborting due to 13 previous errors

View file

@ -2,7 +2,6 @@
//@no-rustfix: overlapping suggestions
#![allow(clippy::no_effect, clippy::unnecessary_operation, clippy::useless_vec, unused)]
#![warn(clippy::single_range_in_vec_init)]
#![feature(generic_arg_infer)]
#[macro_use]
extern crate proc_macros;

View file

@ -1,5 +1,5 @@
error: an array of `Range` that is only one element
--> tests/ui/single_range_in_vec_init.rs:26:5
--> tests/ui/single_range_in_vec_init.rs:25:5
|
LL | [0..200];
| ^^^^^^^^
@ -18,7 +18,7 @@ LL + [0; 200];
|
error: a `Vec` of `Range` that is only one element
--> tests/ui/single_range_in_vec_init.rs:28:5
--> tests/ui/single_range_in_vec_init.rs:27:5
|
LL | vec![0..200];
| ^^^^^^^^^^^^
@ -35,7 +35,7 @@ LL + vec![0; 200];
|
error: an array of `Range` that is only one element
--> tests/ui/single_range_in_vec_init.rs:30:5
--> tests/ui/single_range_in_vec_init.rs:29:5
|
LL | [0u8..200];
| ^^^^^^^^^^
@ -52,7 +52,7 @@ LL + [0u8; 200];
|
error: an array of `Range` that is only one element
--> tests/ui/single_range_in_vec_init.rs:32:5
--> tests/ui/single_range_in_vec_init.rs:31:5
|
LL | [0usize..200];
| ^^^^^^^^^^^^^
@ -69,7 +69,7 @@ LL + [0usize; 200];
|
error: an array of `Range` that is only one element
--> tests/ui/single_range_in_vec_init.rs:34:5
--> tests/ui/single_range_in_vec_init.rs:33:5
|
LL | [0..200usize];
| ^^^^^^^^^^^^^
@ -86,7 +86,7 @@ LL + [0; 200usize];
|
error: a `Vec` of `Range` that is only one element
--> tests/ui/single_range_in_vec_init.rs:36:5
--> tests/ui/single_range_in_vec_init.rs:35:5
|
LL | vec![0u8..200];
| ^^^^^^^^^^^^^^
@ -103,7 +103,7 @@ LL + vec![0u8; 200];
|
error: a `Vec` of `Range` that is only one element
--> tests/ui/single_range_in_vec_init.rs:38:5
--> tests/ui/single_range_in_vec_init.rs:37:5
|
LL | vec![0usize..200];
| ^^^^^^^^^^^^^^^^^
@ -120,7 +120,7 @@ LL + vec![0usize; 200];
|
error: a `Vec` of `Range` that is only one element
--> tests/ui/single_range_in_vec_init.rs:40:5
--> tests/ui/single_range_in_vec_init.rs:39:5
|
LL | vec![0..200usize];
| ^^^^^^^^^^^^^^^^^
@ -137,7 +137,7 @@ LL + vec![0; 200usize];
|
error: an array of `Range` that is only one element
--> tests/ui/single_range_in_vec_init.rs:43:5
--> tests/ui/single_range_in_vec_init.rs:42:5
|
LL | [0..200isize];
| ^^^^^^^^^^^^^
@ -149,7 +149,7 @@ LL + (0..200isize).collect::<std::vec::Vec<isize>>();
|
error: a `Vec` of `Range` that is only one element
--> tests/ui/single_range_in_vec_init.rs:45:5
--> tests/ui/single_range_in_vec_init.rs:44:5
|
LL | vec![0..200isize];
| ^^^^^^^^^^^^^^^^^