Merge commit 'd9fb15c4b1' into clippy-subtree-update
This commit is contained in:
parent
2c8a9e255d
commit
8f61305722
470 changed files with 7419 additions and 2697 deletions
4
.github/workflows/remark.yml
vendored
4
.github/workflows/remark.yml
vendored
|
|
@ -17,9 +17,9 @@ jobs:
|
|||
persist-credentials: false
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@v5
|
||||
with:
|
||||
node-version: '18.x'
|
||||
node-version: '20.x'
|
||||
|
||||
- name: Install remark
|
||||
run: npm install remark-cli remark-lint remark-lint-maximum-line-length@^3.1.3 remark-preset-lint-recommended remark-gfm
|
||||
|
|
|
|||
377
CHANGELOG.md
377
CHANGELOG.md
File diff suppressed because it is too large
Load diff
|
|
@ -759,8 +759,7 @@ for some users. Adding a configuration is done in the following steps:
|
|||
Here are some pointers to things you are likely going to need for every lint:
|
||||
|
||||
* [Clippy utils][utils] - Various helper functions. Maybe the function you need
|
||||
is already in here ([`is_type_diagnostic_item`], [`implements_trait`],
|
||||
[`snippet`], etc)
|
||||
is already in here ([`implements_trait`], [`snippet`], etc)
|
||||
* [Clippy diagnostics][diagnostics]
|
||||
* [Let chains][let-chains]
|
||||
* [`from_expansion`][from_expansion] and
|
||||
|
|
@ -790,7 +789,6 @@ get away with copying things from existing similar lints. If you are stuck,
|
|||
don't hesitate to ask on [Zulip] or in the issue/PR.
|
||||
|
||||
[utils]: https://doc.rust-lang.org/nightly/nightly-rustc/clippy_utils/index.html
|
||||
[`is_type_diagnostic_item`]: https://doc.rust-lang.org/nightly/nightly-rustc/clippy_utils/ty/fn.is_type_diagnostic_item.html
|
||||
[`implements_trait`]: https://doc.rust-lang.org/nightly/nightly-rustc/clippy_utils/ty/fn.implements_trait.html
|
||||
[`snippet`]: https://doc.rust-lang.org/nightly/nightly-rustc/clippy_utils/source/fn.snippet.html
|
||||
[let-chains]: https://github.com/rust-lang/rust/pull/94927
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ impl<'tcx> LateLintPass<'tcx> for MyStructLint {
|
|||
// Check our expr is calling a method
|
||||
if let hir::ExprKind::MethodCall(path, _, _self_arg, ..) = &expr.kind
|
||||
// Check the name of this method is `some_method`
|
||||
&& path.ident.name.as_str() == "some_method"
|
||||
&& path.ident.name == sym::some_method
|
||||
// Optionally, check the type of the self argument.
|
||||
// - See "Checking for a specific type"
|
||||
{
|
||||
|
|
@ -85,9 +85,8 @@ to check for. All of these methods only check for the base type, generic
|
|||
arguments have to be checked separately.
|
||||
|
||||
```rust
|
||||
use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item};
|
||||
use clippy_utils::paths;
|
||||
use rustc_span::symbol::sym;
|
||||
use clippy_utils::{paths, sym};
|
||||
use clippy_utils::res::MaybeDef;
|
||||
use rustc_hir::LangItem;
|
||||
|
||||
impl LateLintPass<'_> for MyStructLint {
|
||||
|
|
@ -97,12 +96,12 @@ impl LateLintPass<'_> for MyStructLint {
|
|||
|
||||
// 1. Using diagnostic items
|
||||
// The last argument is the diagnostic item to check for
|
||||
if is_type_diagnostic_item(cx, ty, sym::Option) {
|
||||
if ty.is_diag_item(cx, sym::Option) {
|
||||
// The type is an `Option`
|
||||
}
|
||||
|
||||
// 2. Using lang items
|
||||
if is_type_lang_item(cx, ty, LangItem::RangeFull) {
|
||||
if ty.is_lang_item(cx, LangItem::RangeFull) {
|
||||
// The type is a full range like `.drain(..)`
|
||||
}
|
||||
|
||||
|
|
@ -123,27 +122,29 @@ There are three ways to do this, depending on if the target trait has a
|
|||
diagnostic item, lang item or neither.
|
||||
|
||||
```rust
|
||||
use clippy_utils::sym;
|
||||
use clippy_utils::ty::implements_trait;
|
||||
use clippy_utils::is_trait_method;
|
||||
use rustc_span::symbol::sym;
|
||||
|
||||
impl LateLintPass<'_> for MyStructLint {
|
||||
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||
// 1. Using diagnostic items with the expression
|
||||
// we use `is_trait_method` function from Clippy's utils
|
||||
if is_trait_method(cx, expr, sym::Iterator) {
|
||||
// method call in `expr` belongs to `Iterator` trait
|
||||
|
||||
// 1. Get the `DefId` of the trait.
|
||||
// via lang items
|
||||
let trait_id = cx.tcx.lang_items().drop_trait();
|
||||
// via diagnostic items
|
||||
let trait_id = cx.tcx.get_diagnostic_item(sym::Eq);
|
||||
|
||||
// 2. Check for the trait implementation via the `implements_trait` util.
|
||||
let ty = cx.typeck_results().expr_ty(expr);
|
||||
if trait_id.is_some_and(|id| implements_trait(cx, ty, id, &[])) {
|
||||
// `ty` implements the trait.
|
||||
}
|
||||
|
||||
// 2. Using lang items with the expression type
|
||||
let ty = cx.typeck_results().expr_ty(expr);
|
||||
if cx.tcx.lang_items()
|
||||
// we are looking for the `DefId` of `Drop` trait in lang items
|
||||
.drop_trait()
|
||||
// then we use it with our type `ty` by calling `implements_trait` from Clippy's utils
|
||||
.is_some_and(|id| implements_trait(cx, ty, id, &[])) {
|
||||
// `expr` implements `Drop` trait
|
||||
}
|
||||
// 3. If the trait requires additional generic arguments
|
||||
let trait_id = cx.tcx.lang_items().eq_trait();
|
||||
if trait_id.is_some_and(|id| implements_trait(cx, ty, id, &[ty])) {
|
||||
// `ty` implements `PartialEq<Self>`
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
|
@ -173,7 +174,7 @@ impl<'tcx> LateLintPass<'tcx> for MyTypeImpl {
|
|||
// We can also check it has a parameter `self`
|
||||
&& signature.decl.implicit_self.has_implicit_self()
|
||||
// We can go further and even check if its return type is `String`
|
||||
&& is_type_lang_item(cx, return_ty(cx, impl_item.hir_id), LangItem::String)
|
||||
&& return_ty(cx, impl_item.hir_id).is_lang_item(cx, LangItem::String)
|
||||
{
|
||||
// ...
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ before emitting suggestions to the end user to avoid false positives.
|
|||
|
||||
Several functions are available for working with macros.
|
||||
|
||||
### The `Span.from_expansion` method
|
||||
### The `Span::from_expansion` method
|
||||
|
||||
We could utilize a `span`'s [`from_expansion`] method, which
|
||||
detects if the `span` is from a macro expansion / desugaring.
|
||||
|
|
@ -50,7 +50,7 @@ if expr.span.from_expansion() {
|
|||
}
|
||||
```
|
||||
|
||||
### `Span.ctxt` method
|
||||
### `Span::ctxt` method
|
||||
|
||||
The `span`'s context, given by the method [`ctxt`] and returning [SyntaxContext],
|
||||
represents if the span is from a macro expansion and, if it is, which
|
||||
|
|
|
|||
|
|
@ -15,20 +15,20 @@ the [`ExprKind`] that we can access from `expr.kind`:
|
|||
```rust
|
||||
use rustc_hir as hir;
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_span::sym;
|
||||
use clippy_utils::is_trait_method;
|
||||
use clippy_utils::res::{MaybeDef, MaybeTypeckRes};
|
||||
use clippy_utils::sym;
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for OurFancyMethodLint {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
|
||||
// Check our expr is calling a method with pattern matching
|
||||
if let hir::ExprKind::MethodCall(path, _, [self_arg, ..], _) = &expr.kind
|
||||
// Check if the name of this method is `our_fancy_method`
|
||||
&& path.ident.name.as_str() == "our_fancy_method"
|
||||
&& path.ident.name == sym::our_fancy_method
|
||||
// We can check the type of the self argument whenever necessary.
|
||||
// (It's necessary if we want to check that method is specifically belonging to a specific trait,
|
||||
// for example, a `map` method could belong to user-defined trait instead of to `Iterator`)
|
||||
// See the next section for more information.
|
||||
&& is_trait_method(cx, self_arg, sym::OurFancyTrait)
|
||||
&& cx.ty_based_def(self_arg).opt_parent(cx).is_diag_item(cx, sym::OurFancyTrait)
|
||||
{
|
||||
println!("`expr` is a method call for `our_fancy_method`");
|
||||
}
|
||||
|
|
@ -41,6 +41,10 @@ information on the pattern matching. As mentioned in [Define
|
|||
Lints](defining_lints.md#lint-types), the `methods` lint type is full of pattern
|
||||
matching with `MethodCall` in case the reader wishes to explore more.
|
||||
|
||||
New symbols such as `our_fancy_method` need to be added to the `clippy_utils::sym` module.
|
||||
This module extends the list of symbols already provided by the compiler crates
|
||||
in `rustc_span::sym`.
|
||||
|
||||
## Checking if a `impl` block implements a method
|
||||
|
||||
While sometimes we want to check whether a method is being called or not, other
|
||||
|
|
@ -56,11 +60,10 @@ Let us take a look at how we might check for the implementation of
|
|||
`our_fancy_method` on a type:
|
||||
|
||||
```rust
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::return_ty;
|
||||
use clippy_utils::{return_ty, sym};
|
||||
use clippy_utils::res::MaybeDef;
|
||||
use rustc_hir::{ImplItem, ImplItemKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_span::symbol::sym;
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for MyTypeImpl {
|
||||
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<'_>) {
|
||||
|
|
@ -71,7 +74,7 @@ impl<'tcx> LateLintPass<'tcx> for MyTypeImpl {
|
|||
// We can also check it has a parameter `self`
|
||||
&& signature.decl.implicit_self.has_implicit_self()
|
||||
// We can go even further and even check if its return type is `String`
|
||||
&& is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id), sym::String)
|
||||
&& return_ty(cx, impl_item.hir_id).is_diag_item(cx, sym::String)
|
||||
{
|
||||
println!("`our_fancy_method` is implemented!");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,10 +17,10 @@ providing the `LateContext` (`cx`), our expression at hand, and
|
|||
the symbol of the trait in question:
|
||||
|
||||
```rust
|
||||
use clippy_utils::sym;
|
||||
use clippy_utils::ty::implements_trait;
|
||||
use rustc_hir::Expr;
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_span::symbol::sym;
|
||||
|
||||
impl LateLintPass<'_> for CheckIteratorTraitLint {
|
||||
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||
|
|
@ -53,7 +53,7 @@ For instance, if we want to examine whether an expression `expr` implements
|
|||
we can check that the `Ty` of the `expr` implements the trait:
|
||||
|
||||
```rust
|
||||
use clippy_utils::implements_trait;
|
||||
use clippy_utils::ty::implements_trait;
|
||||
use rustc_hir::Expr;
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
|
||||
|
|
@ -79,7 +79,8 @@ If neither diagnostic item nor a language item is available, we can use
|
|||
Below, we check if the given `expr` implements [`core::iter::Step`](https://doc.rust-lang.org/std/iter/trait.Step.html):
|
||||
|
||||
```rust
|
||||
use clippy_utils::{implements_trait, paths};
|
||||
use clippy_utils::paths;
|
||||
use clippy_utils::ty::implements_trait;
|
||||
use rustc_hir::Expr;
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
|
||||
|
|
@ -124,8 +125,8 @@ The following code demonstrates how to do this:
|
|||
```rust
|
||||
|
||||
use rustc_middle::ty::Ty;
|
||||
use clippy_utils::sym;
|
||||
use clippy_utils::ty::implements_trait;
|
||||
use rustc_span::symbol::sym;
|
||||
|
||||
let ty = todo!("Get the `Foo` type to check for a trait implementation");
|
||||
let borrow_id = cx.tcx.get_diagnostic_item(sym::Borrow).unwrap(); // avoid unwrap in real code
|
||||
|
|
|
|||
|
|
@ -671,6 +671,16 @@ A list of paths to types that should be treated as if they do not contain interi
|
|||
* [`mutable_key_type`](https://rust-lang.github.io/rust-clippy/master/index.html#mutable_key_type)
|
||||
|
||||
|
||||
## `inherent-impl-lint-scope`
|
||||
Sets the scope ("crate", "file", or "module") in which duplicate inherent `impl` blocks for the same type are linted.
|
||||
|
||||
**Default Value:** `"crate"`
|
||||
|
||||
---
|
||||
**Affected lints:**
|
||||
* [`multiple_inherent_impl`](https://rust-lang.github.io/rust-clippy/master/index.html#multiple_inherent_impl)
|
||||
|
||||
|
||||
## `large-error-threshold`
|
||||
The maximum size of the `Err`-variant in a `Result` returned from a function
|
||||
|
||||
|
|
@ -927,6 +937,16 @@ exported visibility, or whether they are marked as "pub".
|
|||
* [`pub_underscore_fields`](https://rust-lang.github.io/rust-clippy/master/index.html#pub_underscore_fields)
|
||||
|
||||
|
||||
## `recursive-self-in-type-definitions`
|
||||
Whether the type itself in a struct or enum should be replaced with `Self` when encountering recursive types.
|
||||
|
||||
**Default Value:** `true`
|
||||
|
||||
---
|
||||
**Affected lints:**
|
||||
* [`use_self`](https://rust-lang.github.io/rust-clippy/master/index.html#use_self)
|
||||
|
||||
|
||||
## `semicolon-inside-block-ignore-singleline`
|
||||
Whether to lint only if it's multiline.
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
use crate::ClippyConfiguration;
|
||||
use crate::types::{
|
||||
DisallowedPath, DisallowedPathWithoutReplacement, MacroMatcher, MatchLintBehaviour, PubUnderscoreFieldsBehaviour,
|
||||
Rename, SourceItemOrdering, SourceItemOrderingCategory, SourceItemOrderingModuleItemGroupings,
|
||||
SourceItemOrderingModuleItemKind, SourceItemOrderingTraitAssocItemKind, SourceItemOrderingTraitAssocItemKinds,
|
||||
SourceItemOrderingWithinModuleItemGroupings,
|
||||
DisallowedPath, DisallowedPathWithoutReplacement, InherentImplLintScope, MacroMatcher, MatchLintBehaviour,
|
||||
PubUnderscoreFieldsBehaviour, Rename, SourceItemOrdering, SourceItemOrderingCategory,
|
||||
SourceItemOrderingModuleItemGroupings, SourceItemOrderingModuleItemKind, SourceItemOrderingTraitAssocItemKind,
|
||||
SourceItemOrderingTraitAssocItemKinds, SourceItemOrderingWithinModuleItemGroupings,
|
||||
};
|
||||
use clippy_utils::msrvs::Msrv;
|
||||
use itertools::Itertools;
|
||||
|
|
@ -248,7 +248,7 @@ macro_rules! define_Conf {
|
|||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(field_identifier, rename_all = "kebab-case")]
|
||||
#[allow(non_camel_case_types)]
|
||||
#[expect(non_camel_case_types)]
|
||||
enum Field { $($name,)* third_party, }
|
||||
|
||||
struct ConfVisitor<'a>(&'a SourceFile);
|
||||
|
|
@ -663,6 +663,9 @@ define_Conf! {
|
|||
/// A list of paths to types that should be treated as if they do not contain interior mutability
|
||||
#[lints(borrow_interior_mutable_const, declare_interior_mutable_const, ifs_same_cond, mutable_key_type)]
|
||||
ignore_interior_mutability: Vec<String> = Vec::from(["bytes::Bytes".into()]),
|
||||
/// Sets the scope ("crate", "file", or "module") in which duplicate inherent `impl` blocks for the same type are linted.
|
||||
#[lints(multiple_inherent_impl)]
|
||||
inherent_impl_lint_scope: InherentImplLintScope = InherentImplLintScope::Crate,
|
||||
/// The maximum size of the `Err`-variant in a `Result` returned from a function
|
||||
#[lints(result_large_err)]
|
||||
large_error_threshold: u64 = 128,
|
||||
|
|
@ -809,6 +812,9 @@ define_Conf! {
|
|||
/// exported visibility, or whether they are marked as "pub".
|
||||
#[lints(pub_underscore_fields)]
|
||||
pub_underscore_fields_behavior: PubUnderscoreFieldsBehaviour = PubUnderscoreFieldsBehaviour::PubliclyExported,
|
||||
/// Whether the type itself in a struct or enum should be replaced with `Self` when encountering recursive types.
|
||||
#[lints(use_self)]
|
||||
recursive_self_in_type_definitions: bool = true,
|
||||
/// Whether to lint only if it's multiline.
|
||||
#[lints(semicolon_inside_block)]
|
||||
semicolon_inside_block_ignore_singleline: bool = false,
|
||||
|
|
@ -1213,7 +1219,7 @@ mod tests {
|
|||
|
||||
for entry in toml_files {
|
||||
let file = fs::read_to_string(entry.path()).unwrap();
|
||||
#[allow(clippy::zero_sized_map_values)]
|
||||
#[expect(clippy::zero_sized_map_values)]
|
||||
if let Ok(map) = toml::from_str::<HashMap<String, IgnoredAny>>(&file) {
|
||||
for name in map.keys() {
|
||||
names.remove(name.as_str());
|
||||
|
|
|
|||
|
|
@ -131,7 +131,7 @@ impl DisallowedPathEnum {
|
|||
}
|
||||
|
||||
/// Creates a map of disallowed items to the reason they were disallowed.
|
||||
#[allow(clippy::type_complexity)]
|
||||
#[expect(clippy::type_complexity)]
|
||||
pub fn create_disallowed_map<const REPLACEMENT_ALLOWED: bool>(
|
||||
tcx: TyCtxt<'_>,
|
||||
disallowed_paths: &'static [DisallowedPath<REPLACEMENT_ALLOWED>],
|
||||
|
|
@ -698,3 +698,11 @@ pub enum PubUnderscoreFieldsBehaviour {
|
|||
PubliclyExported,
|
||||
AllPubFields,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize, Serialize)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum InherentImplLintScope {
|
||||
Crate,
|
||||
File,
|
||||
Module,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use itertools::Itertools;
|
|||
/// # Panics
|
||||
///
|
||||
/// Panics if unable to run the dogfood test
|
||||
#[allow(clippy::fn_params_excessive_bools)]
|
||||
#[expect(clippy::fn_params_excessive_bools)]
|
||||
pub fn dogfood(fix: bool, allow_dirty: bool, allow_staged: bool, allow_no_vcs: bool) {
|
||||
run_exit_on_err(
|
||||
"cargo test",
|
||||
|
|
|
|||
|
|
@ -192,7 +192,7 @@ enum DevCommand {
|
|||
/// Which lint's page to load initially (optional)
|
||||
lint: Option<String>,
|
||||
},
|
||||
#[allow(clippy::doc_markdown)]
|
||||
#[expect(clippy::doc_markdown)]
|
||||
/// Manually run clippy on a file or package
|
||||
///
|
||||
/// ## Examples
|
||||
|
|
|
|||
|
|
@ -443,7 +443,6 @@ fn create_lint_for_ty(lint: &LintData<'_>, enable_msrv: bool, ty: &str) -> io::R
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_lines)]
|
||||
fn setup_mod_file(path: &Path, lint: &LintData<'_>) -> io::Result<&'static str> {
|
||||
let lint_name_upper = lint.name.to_uppercase();
|
||||
|
||||
|
|
|
|||
|
|
@ -167,7 +167,7 @@ declare_clippy_lint! {
|
|||
impl_lint_pass!(ArbitrarySourceItemOrdering => [ARBITRARY_SOURCE_ITEM_ORDERING]);
|
||||
|
||||
#[derive(Debug)]
|
||||
#[allow(clippy::struct_excessive_bools)] // Bools are cached feature flags.
|
||||
#[expect(clippy::struct_excessive_bools, reason = "Bools are cached feature flags")]
|
||||
pub struct ArbitrarySourceItemOrdering {
|
||||
assoc_types_order: SourceItemOrderingTraitAssocItemKinds,
|
||||
enable_ordering_for_enum: bool,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::is_from_proc_macro;
|
||||
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
|
||||
use clippy_utils::res::MaybeDef;
|
||||
use clippy_utils::ty::implements_trait;
|
||||
use rustc_hir::{Expr, ExprKind, QPath};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty;
|
||||
|
|
@ -46,7 +47,7 @@ impl<'tcx> LateLintPass<'tcx> for ArcWithNonSendSync {
|
|||
&& let ExprKind::Path(QPath::TypeRelative(func_ty, func_name)) = func.kind
|
||||
&& func_name.ident.name == sym::new
|
||||
&& !expr.span.from_expansion()
|
||||
&& is_type_diagnostic_item(cx, cx.typeck_results().node_type(func_ty.hir_id), sym::Arc)
|
||||
&& cx.typeck_results().node_type(func_ty.hir_id).is_diag_item(cx, sym::Arc)
|
||||
&& let arg_ty = cx.typeck_results().expr_ty(arg)
|
||||
// make sure that the type is not and does not contain any type parameters
|
||||
&& arg_ty.walk().all(|arg| {
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::macros::{PanicExpn, find_assert_args, root_macro_call_first_node};
|
||||
use clippy_utils::res::{MaybeDef, MaybeResPath};
|
||||
use clippy_utils::source::snippet_with_context;
|
||||
use clippy_utils::ty::{has_debug_impl, is_copy, is_type_diagnostic_item};
|
||||
use clippy_utils::sym;
|
||||
use clippy_utils::ty::{has_debug_impl, is_copy};
|
||||
use clippy_utils::usage::local_used_after_expr;
|
||||
use clippy_utils::{path_res, sym};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_hir::{Expr, ExprKind, Node};
|
||||
|
|
@ -55,13 +56,13 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnResultStates {
|
|||
&& let ExprKind::MethodCall(method_segment, recv, [], _) = condition.kind
|
||||
&& let result_type_with_refs = cx.typeck_results().expr_ty(recv)
|
||||
&& let result_type = result_type_with_refs.peel_refs()
|
||||
&& is_type_diagnostic_item(cx, result_type, sym::Result)
|
||||
&& result_type.is_diag_item(cx, sym::Result)
|
||||
&& let ty::Adt(_, args) = result_type.kind()
|
||||
{
|
||||
if !is_copy(cx, result_type) {
|
||||
if result_type_with_refs != result_type {
|
||||
return;
|
||||
} else if let Res::Local(binding_id) = path_res(cx, recv)
|
||||
} else if let Res::Local(binding_id) = *recv.basic_res()
|
||||
&& local_used_after_expr(cx, binding_id, recv)
|
||||
{
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -2,8 +2,9 @@ use clippy_config::Conf;
|
|||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::mir::{PossibleBorrowerMap, enclosing_mir};
|
||||
use clippy_utils::msrvs::{self, Msrv};
|
||||
use clippy_utils::res::{MaybeDef, MaybeResPath};
|
||||
use clippy_utils::sugg::Sugg;
|
||||
use clippy_utils::{is_diag_trait_item, is_in_test, last_path_segment, local_is_initialized, path_to_local, sym};
|
||||
use clippy_utils::{is_in_test, last_path_segment, local_is_initialized, sym};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{self as hir, Expr, ExprKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
|
|
@ -68,15 +69,15 @@ impl<'tcx> LateLintPass<'tcx> for AssigningClones {
|
|||
fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
|
||||
if let ExprKind::Assign(lhs, rhs, _) = e.kind
|
||||
&& let typeck = cx.typeck_results()
|
||||
&& let (call_kind, fn_name, fn_id, fn_arg, fn_gen_args) = match rhs.kind {
|
||||
&& let (call_kind, fn_name, fn_def, fn_arg, fn_gen_args) = match rhs.kind {
|
||||
ExprKind::Call(f, [arg])
|
||||
if let ExprKind::Path(fn_path) = &f.kind
|
||||
&& let Some(id) = typeck.qpath_res(fn_path, f.hir_id).opt_def_id() =>
|
||||
&& let Some(def) = typeck.qpath_res(fn_path, f.hir_id).opt_def(cx) =>
|
||||
{
|
||||
(CallKind::Ufcs, last_path_segment(fn_path).ident.name, id, arg, typeck.node_args(f.hir_id))
|
||||
(CallKind::Ufcs, last_path_segment(fn_path).ident.name, def, arg, typeck.node_args(f.hir_id))
|
||||
},
|
||||
ExprKind::MethodCall(name, recv, [], _) if let Some(id) = typeck.type_dependent_def_id(rhs.hir_id) => {
|
||||
(CallKind::Method, name.ident.name, id, recv, typeck.node_args(rhs.hir_id))
|
||||
ExprKind::MethodCall(name, recv, [], _) if let Some(def) = typeck.type_dependent_def(rhs.hir_id) => {
|
||||
(CallKind::Method, name.ident.name, def, recv, typeck.node_args(rhs.hir_id))
|
||||
},
|
||||
_ => return,
|
||||
}
|
||||
|
|
@ -84,20 +85,20 @@ impl<'tcx> LateLintPass<'tcx> for AssigningClones {
|
|||
// Don't lint in macros.
|
||||
&& ctxt.is_root()
|
||||
&& let which_trait = match fn_name {
|
||||
sym::clone if is_diag_trait_item(cx, fn_id, sym::Clone) => CloneTrait::Clone,
|
||||
sym::clone if fn_def.assoc_fn_parent(cx).is_diag_item(cx, sym::Clone) => CloneTrait::Clone,
|
||||
sym::to_owned
|
||||
if is_diag_trait_item(cx, fn_id, sym::ToOwned)
|
||||
if fn_def.assoc_fn_parent(cx).is_diag_item(cx, sym::ToOwned)
|
||||
&& self.msrv.meets(cx, msrvs::CLONE_INTO) =>
|
||||
{
|
||||
CloneTrait::ToOwned
|
||||
},
|
||||
_ => return,
|
||||
}
|
||||
&& let Ok(Some(resolved_fn)) = Instance::try_resolve(cx.tcx, cx.typing_env(), fn_id, fn_gen_args)
|
||||
&& let Ok(Some(resolved_fn)) = Instance::try_resolve(cx.tcx, cx.typing_env(), fn_def.1, fn_gen_args)
|
||||
// TODO: This check currently bails if the local variable has no initializer.
|
||||
// That is overly conservative - the lint should fire even if there was no initializer,
|
||||
// but the variable has been initialized before `lhs` was evaluated.
|
||||
&& path_to_local(lhs).is_none_or(|lhs| local_is_initialized(cx, lhs))
|
||||
&& lhs.res_local_id().is_none_or(|lhs| local_is_initialized(cx, lhs))
|
||||
&& let Some(resolved_impl) = cx.tcx.impl_of_assoc(resolved_fn.def_id())
|
||||
// Derived forms don't implement `clone_from`/`clone_into`.
|
||||
// See https://github.com/rust-lang/rust/pull/98445#issuecomment-1190681305
|
||||
|
|
|
|||
|
|
@ -2,9 +2,10 @@ use clippy_config::Conf;
|
|||
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then};
|
||||
use clippy_utils::higher::has_let_expr;
|
||||
use clippy_utils::msrvs::{self, Msrv};
|
||||
use clippy_utils::res::MaybeDef;
|
||||
use clippy_utils::source::SpanRangeExt;
|
||||
use clippy_utils::sugg::Sugg;
|
||||
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
|
||||
use clippy_utils::ty::implements_trait;
|
||||
use clippy_utils::{eq_expr_value, sym};
|
||||
use rustc_ast::ast::LitKind;
|
||||
use rustc_errors::Applicability;
|
||||
|
|
@ -431,9 +432,7 @@ fn simplify_not(cx: &LateContext<'_>, curr_msrv: Msrv, expr: &Expr<'_>) -> Optio
|
|||
},
|
||||
ExprKind::MethodCall(path, receiver, args, _) => {
|
||||
let type_of_receiver = cx.typeck_results().expr_ty(receiver);
|
||||
if !is_type_diagnostic_item(cx, type_of_receiver, sym::Option)
|
||||
&& !is_type_diagnostic_item(cx, type_of_receiver, sym::Result)
|
||||
{
|
||||
if !type_of_receiver.is_diag_item(cx, sym::Option) && !type_of_receiver.is_diag_item(cx, sym::Result) {
|
||||
return None;
|
||||
}
|
||||
METHODS_WITH_NEGATION
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::is_default_equivalent;
|
||||
use clippy_utils::macros::macro_backtrace;
|
||||
use clippy_utils::res::{MaybeDef, MaybeResPath};
|
||||
use clippy_utils::ty::expr_sig;
|
||||
use clippy_utils::{is_default_equivalent, path_def_id};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_hir::intravisit::{InferKind, Visitor, VisitorExt, walk_ty};
|
||||
use rustc_hir::{AmbigArg, Block, Expr, ExprKind, HirId, LetStmt, Node, QPath, Ty, TyKind};
|
||||
use rustc_hir::{AmbigArg, Block, Expr, ExprKind, HirId, LangItem, LetStmt, Node, QPath, Ty, TyKind};
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
use rustc_session::declare_lint_pass;
|
||||
use rustc_span::{Span, sym};
|
||||
|
|
@ -44,7 +45,7 @@ impl LateLintPass<'_> for BoxDefault {
|
|||
// And that method is `new`
|
||||
&& seg.ident.name == sym::new
|
||||
// And the call is that of a `Box` method
|
||||
&& path_def_id(cx, ty).is_some_and(|id| Some(id) == cx.tcx.lang_items().owned_box())
|
||||
&& ty.basic_res().is_lang_item(cx, LangItem::OwnedBox)
|
||||
// And the single argument to the call is another function call
|
||||
// This is the `T::default()` (or default equivalent) of `Box::new(T::default())`
|
||||
&& let ExprKind::Call(arg_path, _) = arg.kind
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::res::{MaybeDef, MaybeResPath};
|
||||
use clippy_utils::source::SpanRangeExt;
|
||||
use clippy_utils::{expr_or_init, is_path_diagnostic_item, std_or_core, sym};
|
||||
use clippy_utils::{expr_or_init, std_or_core, sym};
|
||||
use rustc_ast::LitKind;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, ExprKind, GenericArg, Mutability, QPath, Ty, TyKind};
|
||||
|
|
@ -53,7 +54,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
|
||||
&& is_path_diagnostic_item(cx, fun, sym::mem_align_of)
|
||||
&& fun.basic_res().is_diag_item(cx, sym::mem_align_of)
|
||||
&& let Some(args) = path.segments.last().and_then(|seg| seg.args)
|
||||
&& let [GenericArg::Type(generic_ty)] = args.args
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::numeric_literal::NumericLiteral;
|
||||
use clippy_utils::res::MaybeResPath;
|
||||
use clippy_utils::source::{SpanRangeExt, snippet_opt};
|
||||
use clippy_utils::visitors::{Visitable, for_each_expr_without_closures};
|
||||
use clippy_utils::{get_parent_expr, is_hir_ty_cfg_dependant, is_ty_alias, path_to_local};
|
||||
use clippy_utils::{get_parent_expr, is_hir_ty_cfg_dependant, is_ty_alias};
|
||||
use rustc_ast::{LitFloatType, LitIntType, LitKind};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
|
|
@ -167,11 +168,11 @@ pub(super) fn check<'tcx>(
|
|||
sym::assert_ne_macro,
|
||||
sym::debug_assert_ne_macro,
|
||||
];
|
||||
matches!(expr.span.ctxt().outer_expn_data().macro_def_id, Some(def_id) if
|
||||
matches!(expr.span.ctxt().outer_expn_data().macro_def_id, Some(def_id) if
|
||||
cx.tcx.get_diagnostic_name(def_id).is_some_and(|sym| ALLOWED_MACROS.contains(&sym)))
|
||||
}
|
||||
|
||||
if let Some(id) = path_to_local(cast_expr)
|
||||
if let Some(id) = cast_expr.res_local_id()
|
||||
&& !cx.tcx.hir_span(id).eq_ctxt(cast_expr.span)
|
||||
{
|
||||
// Binding context is different than the identifiers context.
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::msrvs::{self, Msrv};
|
||||
use clippy_utils::res::{MaybeDef, MaybeTypeckRes};
|
||||
use clippy_utils::sugg::Sugg;
|
||||
use clippy_utils::visitors::is_const_evaluatable;
|
||||
use clippy_utils::{is_in_const_context, is_mutable, is_trait_method};
|
||||
use clippy_utils::{is_in_const_context, is_mutable};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, ExprKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
|
|
@ -73,7 +74,7 @@ impl<'tcx> LateLintPass<'tcx> for ClonedRefToSliceRefs<'_> {
|
|||
|
||||
// check for clones
|
||||
&& let ExprKind::MethodCall(_, val, _, _) = item.kind
|
||||
&& is_trait_method(cx, item, sym::Clone)
|
||||
&& cx.ty_based_def(item).opt_parent(cx).is_diag_item(cx, sym::Clone)
|
||||
|
||||
// check for immutability or purity
|
||||
&& (!is_mutable(cx, val) || is_const_evaluatable(cx, val))
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use clippy_utils::res::MaybeDef;
|
||||
use clippy_utils::source::{IntoSpan, SpanRangeExt};
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::visitors::for_each_expr_without_closures;
|
||||
use clippy_utils::{LimitStack, get_async_fn_body, sym};
|
||||
use core::ops::ControlFlow;
|
||||
|
|
@ -93,7 +93,7 @@ impl CognitiveComplexity {
|
|||
});
|
||||
|
||||
let ret_ty = cx.typeck_results().node_type(expr.hir_id);
|
||||
let ret_adjust = if is_type_diagnostic_item(cx, ret_ty, sym::Result) {
|
||||
let ret_adjust = if ret_ty.is_diag_item(cx, sym::Result) {
|
||||
returns
|
||||
} else {
|
||||
#[expect(clippy::integer_division)]
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use clippy_utils::diagnostics::span_lint;
|
||||
use clippy_utils::ty::{get_type_diagnostic_name, is_type_lang_item};
|
||||
use clippy_utils::get_enclosing_block;
|
||||
use clippy_utils::res::{MaybeDef, MaybeResPath};
|
||||
use clippy_utils::visitors::{Visitable, for_each_expr};
|
||||
use clippy_utils::{get_enclosing_block, path_to_local_id};
|
||||
use core::ops::ControlFlow;
|
||||
use rustc_hir::{Body, ExprKind, HirId, LangItem, LetStmt, Node, PatKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
|
|
@ -59,7 +59,7 @@ impl<'tcx> LateLintPass<'tcx> for CollectionIsNeverRead {
|
|||
fn match_acceptable_type(cx: &LateContext<'_>, local: &LetStmt<'_>) -> bool {
|
||||
let ty = cx.typeck_results().pat_ty(local.pat);
|
||||
matches!(
|
||||
get_type_diagnostic_name(cx, ty),
|
||||
ty.opt_diag_name(cx),
|
||||
Some(
|
||||
sym::BTreeMap
|
||||
| sym::BTreeSet
|
||||
|
|
@ -71,7 +71,7 @@ fn match_acceptable_type(cx: &LateContext<'_>, local: &LetStmt<'_>) -> bool {
|
|||
| sym::Vec
|
||||
| sym::VecDeque
|
||||
)
|
||||
) || is_type_lang_item(cx, ty, LangItem::String)
|
||||
) || ty.is_lang_item(cx, LangItem::String)
|
||||
}
|
||||
|
||||
fn has_no_read_access<'tcx, T: Visitable<'tcx>>(cx: &LateContext<'tcx>, id: HirId, block: T) -> bool {
|
||||
|
|
@ -81,7 +81,7 @@ fn has_no_read_access<'tcx, T: Visitable<'tcx>>(cx: &LateContext<'tcx>, id: HirI
|
|||
// Inspect all expressions and sub-expressions in the block.
|
||||
for_each_expr(cx, block, |expr| {
|
||||
// Ignore expressions that are not simply `id`.
|
||||
if !path_to_local_id(expr, id) {
|
||||
if expr.res_local_id() != Some(id) {
|
||||
return ControlFlow::Continue(());
|
||||
}
|
||||
|
||||
|
|
@ -93,7 +93,7 @@ fn has_no_read_access<'tcx, T: Visitable<'tcx>>(cx: &LateContext<'tcx>, id: HirI
|
|||
// id = ...; // Not reading `id`.
|
||||
if let Node::Expr(parent) = cx.tcx.parent_hir_node(expr.hir_id)
|
||||
&& let ExprKind::Assign(lhs, ..) = parent.kind
|
||||
&& path_to_local_id(lhs, id)
|
||||
&& lhs.res_local_id() == Some(id)
|
||||
{
|
||||
return ControlFlow::Continue(());
|
||||
}
|
||||
|
|
@ -107,7 +107,7 @@ fn has_no_read_access<'tcx, T: Visitable<'tcx>>(cx: &LateContext<'tcx>, id: HirI
|
|||
// have side effects, so consider them a read.
|
||||
if let Node::Expr(parent) = cx.tcx.parent_hir_node(expr.hir_id)
|
||||
&& let ExprKind::MethodCall(_, receiver, args, _) = parent.kind
|
||||
&& path_to_local_id(receiver, id)
|
||||
&& receiver.res_local_id() == Some(id)
|
||||
&& let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(parent.hir_id)
|
||||
&& !method_def_id.is_local()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -488,6 +488,7 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[
|
|||
crate::methods::UNNECESSARY_LITERAL_UNWRAP_INFO,
|
||||
crate::methods::UNNECESSARY_MAP_OR_INFO,
|
||||
crate::methods::UNNECESSARY_MIN_OR_MAX_INFO,
|
||||
crate::methods::UNNECESSARY_OPTION_MAP_OR_ELSE_INFO,
|
||||
crate::methods::UNNECESSARY_RESULT_MAP_OR_ELSE_INFO,
|
||||
crate::methods::UNNECESSARY_SORT_BY_INFO,
|
||||
crate::methods::UNNECESSARY_TO_OWNED_INFO,
|
||||
|
|
@ -655,6 +656,7 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[
|
|||
crate::regex::REGEX_CREATION_IN_LOOPS_INFO,
|
||||
crate::regex::TRIVIAL_REGEX_INFO,
|
||||
crate::repeat_vec_with_capacity::REPEAT_VEC_WITH_CAPACITY_INFO,
|
||||
crate::replace_box::REPLACE_BOX_INFO,
|
||||
crate::reserve_after_initialization::RESERVE_AFTER_INITIALIZATION_INFO,
|
||||
crate::return_self_not_must_use::RETURN_SELF_NOT_MUST_USE_INFO,
|
||||
crate::returns::LET_AND_RETURN_INFO,
|
||||
|
|
@ -780,6 +782,7 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[
|
|||
crate::visibility::NEEDLESS_PUB_SELF_INFO,
|
||||
crate::visibility::PUB_WITHOUT_SHORTHAND_INFO,
|
||||
crate::visibility::PUB_WITH_SHORTHAND_INFO,
|
||||
crate::volatile_composites::VOLATILE_COMPOSITES_INFO,
|
||||
crate::wildcard_imports::ENUM_GLOB_USE_INFO,
|
||||
crate::wildcard_imports::WILDCARD_IMPORTS_INFO,
|
||||
crate::write::PRINTLN_EMPTY_STRING_INFO,
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ macro_rules! declare_with_version {
|
|||
$e:expr,
|
||||
)*]) => {
|
||||
pub static $name: &[(&str, &str)] = &[$($e),*];
|
||||
#[allow(unused)]
|
||||
pub static $name_version: &[&str] = &[$($version),*];
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then};
|
||||
use clippy_utils::res::MaybeResPath;
|
||||
use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
|
||||
use clippy_utils::sugg::has_enclosing_paren;
|
||||
use clippy_utils::ty::{adjust_derefs_manually_drop, implements_trait, is_manually_drop, peel_and_count_ty_refs};
|
||||
use clippy_utils::{
|
||||
DefinedTy, ExprUseNode, expr_use_ctxt, get_parent_expr, is_block_like, is_from_proc_macro, is_lint_allowed,
|
||||
path_to_local,
|
||||
};
|
||||
use rustc_ast::util::parser::ExprPrecedence;
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
|
|
@ -239,7 +239,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
|
|||
return;
|
||||
}
|
||||
|
||||
if let Some(local) = path_to_local(expr) {
|
||||
if let Some(local) = expr.res_local_id() {
|
||||
self.check_local_usage(cx, expr, local);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use clippy_utils::diagnostics::span_lint_hir_and_then;
|
||||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use clippy_utils::fulfill_or_allowed;
|
||||
use clippy_utils::ty::{implements_trait, is_copy};
|
||||
use rustc_hir::{self as hir, HirId, Item};
|
||||
use rustc_lint::LateContext;
|
||||
|
|
@ -60,14 +61,16 @@ pub(super) fn check<'tcx>(
|
|||
return;
|
||||
}
|
||||
|
||||
span_lint_hir_and_then(
|
||||
if fulfill_or_allowed(cx, EXPL_IMPL_CLONE_ON_COPY, [adt_hir_id]) {
|
||||
return;
|
||||
}
|
||||
|
||||
span_lint_and_help(
|
||||
cx,
|
||||
EXPL_IMPL_CLONE_ON_COPY,
|
||||
adt_hir_id,
|
||||
item.span,
|
||||
"you are implementing `Clone` explicitly on a `Copy` type",
|
||||
|diag| {
|
||||
diag.span_help(item.span, "consider deriving `Clone` or removing `Copy`");
|
||||
},
|
||||
None,
|
||||
"consider deriving `Clone` or removing `Copy`",
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use clippy_utils::path_res;
|
||||
use clippy_utils::res::MaybeResPath;
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_hir::{Impl, Item, ItemKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
|
|
@ -199,7 +199,7 @@ impl<'tcx> LateLintPass<'tcx> for Derive {
|
|||
self_ty,
|
||||
..
|
||||
}) = item.kind
|
||||
&& let Res::Def(_, def_id) = path_res(cx, self_ty)
|
||||
&& let Res::Def(_, def_id) = *self_ty.basic_res()
|
||||
&& let Some(local_def_id) = def_id.as_local()
|
||||
{
|
||||
let adt_hir_id = cx.tcx.local_def_id_to_hir_id(local_def_id);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
use super::{DocHeaders, MISSING_ERRORS_DOC, MISSING_PANICS_DOC, MISSING_SAFETY_DOC, UNNECESSARY_SAFETY_DOC};
|
||||
use clippy_utils::diagnostics::{span_lint, span_lint_and_note};
|
||||
use clippy_utils::macros::{is_panic, root_macro_call_first_node};
|
||||
use clippy_utils::ty::{get_type_diagnostic_name, implements_trait_with_env, is_type_diagnostic_item};
|
||||
use clippy_utils::res::MaybeDef;
|
||||
use clippy_utils::ty::implements_trait_with_env;
|
||||
use clippy_utils::visitors::for_each_expr;
|
||||
use clippy_utils::{fulfill_or_allowed, is_doc_hidden, is_inside_always_const_context, method_chain_args, return_ty};
|
||||
use rustc_hir::{BodyId, FnSig, OwnerId, Safety};
|
||||
|
|
@ -62,7 +63,7 @@ pub fn check(
|
|||
);
|
||||
}
|
||||
if !headers.errors {
|
||||
if is_type_diagnostic_item(cx, return_ty(cx, owner_id), sym::Result) {
|
||||
if return_ty(cx, owner_id).is_diag_item(cx, sym::Result) {
|
||||
span_lint(
|
||||
cx,
|
||||
MISSING_ERRORS_DOC,
|
||||
|
|
@ -83,7 +84,7 @@ pub fn check(
|
|||
&[],
|
||||
)
|
||||
&& let ty::Coroutine(_, subs) = ret_ty.kind()
|
||||
&& is_type_diagnostic_item(cx, subs.as_coroutine().return_ty(), sym::Result)
|
||||
&& subs.as_coroutine().return_ty().is_diag_item(cx, sym::Result)
|
||||
{
|
||||
span_lint(
|
||||
cx,
|
||||
|
|
@ -119,10 +120,7 @@ fn find_panic(cx: &LateContext<'_>, body_id: BodyId) -> Option<Span> {
|
|||
if let Some(arglists) =
|
||||
method_chain_args(expr, &[sym::unwrap]).or_else(|| method_chain_args(expr, &[sym::expect]))
|
||||
&& let receiver_ty = typeck.expr_ty(arglists[0].0).peel_refs()
|
||||
&& matches!(
|
||||
get_type_diagnostic_name(cx, receiver_ty),
|
||||
Some(sym::Option | sym::Result)
|
||||
)
|
||||
&& matches!(receiver_ty.opt_diag_name(cx), Some(sym::Option | sym::Result))
|
||||
&& !fulfill_or_allowed(cx, MISSING_PANICS_DOC, [expr.hir_id])
|
||||
&& panic_span.is_none()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -970,7 +970,7 @@ fn check_for_code_clusters<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a
|
|||
/// This walks the "events" (think sections of markdown) produced by `pulldown_cmark`,
|
||||
/// so lints here will generally access that information.
|
||||
/// Returns documentation headers -- whether a "Safety", "Errors", "Panic" section was found
|
||||
#[allow(clippy::too_many_lines)] // Only a big match statement
|
||||
#[expect(clippy::too_many_lines, reason = "big match statement")]
|
||||
fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize>)>>(
|
||||
cx: &LateContext<'_>,
|
||||
valid_idents: &FxHashSet<String>,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::is_must_use_func_call;
|
||||
use clippy_utils::ty::{is_copy, is_must_use_ty, is_type_lang_item};
|
||||
use clippy_utils::res::MaybeDef;
|
||||
use clippy_utils::ty::{is_copy, is_must_use_ty};
|
||||
use rustc_hir::{Arm, Expr, ExprKind, LangItem, Node};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::declare_lint_pass;
|
||||
|
|
@ -97,7 +98,7 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef {
|
|||
sym::mem_forget if arg_ty.is_ref() => return,
|
||||
sym::mem_drop if is_copy && !drop_is_single_call_in_arm => return,
|
||||
sym::mem_forget if is_copy => return,
|
||||
sym::mem_drop if is_type_lang_item(cx, arg_ty, LangItem::ManuallyDrop) => return,
|
||||
sym::mem_drop if arg_ty.is_lang_item(cx, LangItem::ManuallyDrop) => return,
|
||||
sym::mem_drop
|
||||
if !(arg_ty.needs_drop(cx.tcx, cx.typing_env())
|
||||
|| is_must_use_func_call(cx, arg)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use clippy_utils::diagnostics::{span_lint, span_lint_hir_and_then};
|
||||
use clippy_utils::path_res;
|
||||
use clippy_utils::res::MaybeResPath;
|
||||
use clippy_utils::ty::implements_trait;
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::{Item, ItemKind};
|
||||
|
|
@ -55,7 +55,7 @@ impl<'tcx> LateLintPass<'tcx> for ErrorImplError {
|
|||
if let Some(trait_def_id) = imp.of_trait.and_then(|t| t.trait_ref.trait_def_id())
|
||||
&& let Some(error_def_id) = cx.tcx.get_diagnostic_item(sym::Error)
|
||||
&& error_def_id == trait_def_id
|
||||
&& let Some(def_id) = path_res(cx, imp.self_ty).opt_def_id().and_then(DefId::as_local)
|
||||
&& let Some(def_id) = imp.self_ty.basic_res().opt_def_id().and_then(DefId::as_local)
|
||||
&& let Some(ident) = cx.tcx.opt_item_ident(def_id.to_def_id())
|
||||
&& ident.name == sym::Error
|
||||
&& is_visible_outside_module(cx, def_id) =>
|
||||
|
|
|
|||
|
|
@ -1,11 +1,9 @@
|
|||
use clippy_utils::diagnostics::span_lint_hir_and_then;
|
||||
use clippy_utils::higher::VecArgs;
|
||||
use clippy_utils::res::{MaybeDef, MaybeResPath};
|
||||
use clippy_utils::source::{snippet_opt, snippet_with_applicability};
|
||||
use clippy_utils::ty::get_type_diagnostic_name;
|
||||
use clippy_utils::usage::{local_used_after_expr, local_used_in};
|
||||
use clippy_utils::{
|
||||
get_path_from_caller_to_method_type, is_adjusted, is_no_std_crate, path_to_local, path_to_local_id,
|
||||
};
|
||||
use clippy_utils::{get_path_from_caller_to_method_type, is_adjusted, is_no_std_crate};
|
||||
use rustc_abi::ExternAbi;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
|
|
@ -86,7 +84,7 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_lines)]
|
||||
#[expect(clippy::too_many_lines)]
|
||||
fn check_closure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tcx>>, expr: &Expr<'tcx>) {
|
||||
let body = if let ExprKind::Closure(c) = expr.kind
|
||||
&& c.fn_decl.inputs.iter().all(|ty| matches!(ty.kind, TyKind::Infer(())))
|
||||
|
|
@ -144,7 +142,7 @@ fn check_closure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tcx
|
|||
{
|
||||
let callee_ty_raw = typeck.expr_ty(callee);
|
||||
let callee_ty = callee_ty_raw.peel_refs();
|
||||
if matches!(get_type_diagnostic_name(cx, callee_ty), Some(sym::Arc | sym::Rc))
|
||||
if matches!(callee_ty.opt_diag_name(cx), Some(sym::Arc | sym::Rc))
|
||||
|| !check_inputs(typeck, body.params, None, args)
|
||||
{
|
||||
return;
|
||||
|
|
@ -218,7 +216,7 @@ fn check_closure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tcx
|
|||
"redundant closure",
|
||||
|diag| {
|
||||
if let Some(mut snippet) = snippet_opt(cx, callee.span) {
|
||||
if path_to_local(callee).is_some_and(|l| {
|
||||
if callee.res_local_id().is_some_and(|l| {
|
||||
// FIXME: Do we really need this `local_used_in` check?
|
||||
// Isn't it checking something like... `callee(callee)`?
|
||||
// If somehow this check is needed, add some test for it,
|
||||
|
|
@ -307,7 +305,7 @@ fn check_inputs(
|
|||
matches!(
|
||||
p.pat.kind,
|
||||
PatKind::Binding(BindingMode::NONE, id, _, None)
|
||||
if path_to_local_id(arg, id)
|
||||
if arg.res_local_id() == Some(id)
|
||||
)
|
||||
// Only allow adjustments which change regions (i.e. re-borrowing).
|
||||
&& typeck
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::macros::{FormatArgsStorage, format_args_inputs_span};
|
||||
use clippy_utils::res::MaybeResPath;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::{is_expn_of, path_def_id, sym};
|
||||
use clippy_utils::{is_expn_of, is_in_test, sym};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_hir::{BindingMode, Block, BlockCheckMode, Expr, ExprKind, Node, PatKind, QPath, Stmt, StmtKind};
|
||||
|
|
@ -59,7 +60,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite {
|
|||
&& let ExprKind::MethodCall(write_fun, write_recv, [write_arg], _) = *look_in_block(cx, &write_call.kind)
|
||||
&& let ExprKind::Call(write_recv_path, []) = write_recv.kind
|
||||
&& write_fun.ident.name == sym::write_fmt
|
||||
&& let Some(def_id) = path_def_id(cx, write_recv_path)
|
||||
&& let Some(def_id) = write_recv_path.basic_res().opt_def_id()
|
||||
{
|
||||
// match calls to std::io::stdout() / std::io::stderr ()
|
||||
let (dest_name, prefix) = match cx.tcx.get_diagnostic_name(def_id) {
|
||||
|
|
@ -71,6 +72,11 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite {
|
|||
return;
|
||||
};
|
||||
|
||||
// Performing an explicit write in a test circumvent's libtest's capture of stdio and stdout.
|
||||
if is_in_test(cx.tcx, expr.hir_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
// ordering is important here, since `writeln!` uses `write!` internally
|
||||
let calling_macro = if is_expn_of(write_call.span, sym::writeln).is_some() {
|
||||
Some("writeln")
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::macros::{is_panic, root_macro_call_first_node};
|
||||
use clippy_utils::method_chain_args;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::res::MaybeDef;
|
||||
use rustc_hir as hir;
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty;
|
||||
|
|
@ -84,9 +84,7 @@ fn lint_impl_body(cx: &LateContext<'_>, item_def_id: hir::OwnerId, impl_span: Sp
|
|||
// check for `unwrap`
|
||||
if let Some(arglists) = method_chain_args(expr, &[sym::unwrap]) {
|
||||
let receiver_ty = self.typeck_results.expr_ty(arglists[0].0).peel_refs();
|
||||
if is_type_diagnostic_item(self.lcx, receiver_ty, sym::Option)
|
||||
|| is_type_diagnostic_item(self.lcx, receiver_ty, sym::Result)
|
||||
{
|
||||
if receiver_ty.is_diag_item(self.lcx, sym::Option) || receiver_ty.is_diag_item(self.lcx, sym::Result) {
|
||||
self.result.push(expr.span);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
use clippy_utils::consts::Constant::{F32, F64, Int};
|
||||
use clippy_utils::consts::{ConstEvalCtxt, Constant};
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::res::{MaybeDef, MaybeTypeckRes};
|
||||
use clippy_utils::{
|
||||
eq_expr_value, get_parent_expr, has_ambiguous_literal_in_expr, higher, is_in_const_context,
|
||||
is_inherent_method_call, is_no_std_crate, numeric_literal, peel_blocks, sugg, sym,
|
||||
eq_expr_value, get_parent_expr, has_ambiguous_literal_in_expr, higher, is_in_const_context, is_no_std_crate,
|
||||
numeric_literal, peel_blocks, sugg, sym,
|
||||
};
|
||||
use rustc_ast::ast;
|
||||
use rustc_errors::Applicability;
|
||||
|
|
@ -737,7 +738,7 @@ impl<'tcx> LateLintPass<'tcx> for FloatingPointArithmetic {
|
|||
if let ExprKind::MethodCall(path, receiver, args, _) = &expr.kind {
|
||||
let recv_ty = cx.typeck_results().expr_ty(receiver);
|
||||
|
||||
if recv_ty.is_floating_point() && !is_no_std_crate(cx) && is_inherent_method_call(cx, expr) {
|
||||
if recv_ty.is_floating_point() && !is_no_std_crate(cx) && cx.ty_based_def(expr).opt_parent(cx).is_impl(cx) {
|
||||
match path.ident.name {
|
||||
sym::ln => check_ln1p(cx, expr, receiver),
|
||||
sym::log => check_log_base(cx, expr, receiver, args),
|
||||
|
|
|
|||
|
|
@ -39,7 +39,6 @@ declare_clippy_lint! {
|
|||
"useless use of `format!`"
|
||||
}
|
||||
|
||||
#[allow(clippy::module_name_repetitions)]
|
||||
pub struct UselessFormat {
|
||||
format_args: FormatArgsStorage,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,9 +9,10 @@ use clippy_utils::macros::{
|
|||
root_macro_call_first_node,
|
||||
};
|
||||
use clippy_utils::msrvs::{self, Msrv};
|
||||
use clippy_utils::res::MaybeDef;
|
||||
use clippy_utils::source::{SpanRangeExt, snippet};
|
||||
use clippy_utils::ty::{implements_trait, is_type_lang_item};
|
||||
use clippy_utils::{is_diag_trait_item, is_from_proc_macro, is_in_test, trait_ref_of_method};
|
||||
use clippy_utils::ty::implements_trait;
|
||||
use clippy_utils::{is_from_proc_macro, is_in_test, trait_ref_of_method};
|
||||
use itertools::Itertools;
|
||||
use rustc_ast::{
|
||||
FormatArgPosition, FormatArgPositionKind, FormatArgsPiece, FormatArgumentKind, FormatCount, FormatOptions,
|
||||
|
|
@ -237,7 +238,7 @@ impl_lint_pass!(FormatArgs<'_> => [
|
|||
POINTER_FORMAT,
|
||||
]);
|
||||
|
||||
#[allow(clippy::struct_field_names)]
|
||||
#[expect(clippy::struct_field_names)]
|
||||
pub struct FormatArgs<'tcx> {
|
||||
format_args: FormatArgsStorage,
|
||||
msrv: Msrv,
|
||||
|
|
@ -344,7 +345,7 @@ impl<'tcx> FormatArgsExpr<'_, 'tcx> {
|
|||
if let Some(placeholder_span) = placeholder.span
|
||||
&& *options != FormatOptions::default()
|
||||
&& let ty = self.cx.typeck_results().expr_ty(arg).peel_refs()
|
||||
&& is_type_lang_item(self.cx, ty, LangItem::FormatArguments)
|
||||
&& ty.is_lang_item(self.cx, LangItem::FormatArguments)
|
||||
{
|
||||
span_lint_and_then(
|
||||
self.cx,
|
||||
|
|
@ -497,8 +498,11 @@ impl<'tcx> FormatArgsExpr<'_, 'tcx> {
|
|||
let cx = self.cx;
|
||||
if !value.span.from_expansion()
|
||||
&& let ExprKind::MethodCall(_, receiver, [], to_string_span) = value.kind
|
||||
&& let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(value.hir_id)
|
||||
&& is_diag_trait_item(cx, method_def_id, sym::ToString)
|
||||
&& cx
|
||||
.typeck_results()
|
||||
.type_dependent_def_id(value.hir_id)
|
||||
.opt_parent(cx)
|
||||
.is_diag_item(cx, sym::ToString)
|
||||
&& let receiver_ty = cx.typeck_results().expr_ty(receiver)
|
||||
&& let Some(display_trait_id) = cx.tcx.get_diagnostic_item(sym::Display)
|
||||
&& let (n_needed_derefs, target) =
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
|
||||
use clippy_utils::macros::{FormatArgsStorage, find_format_arg_expr, is_format_macro, root_macro_call_first_node};
|
||||
use clippy_utils::{get_parent_as_impl, is_diag_trait_item, path_to_local, peel_ref_operators, sym};
|
||||
use clippy_utils::res::{MaybeDef, MaybeResPath};
|
||||
use clippy_utils::{get_parent_as_impl, peel_ref_operators, sym};
|
||||
use rustc_ast::{FormatArgsPiece, FormatTrait};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, ExprKind, Impl, ImplItem, ImplItemKind, QPath};
|
||||
|
|
@ -157,8 +158,12 @@ impl FormatImplExpr<'_, '_> {
|
|||
&& path.ident.name == sym::to_string
|
||||
// Is the method a part of the ToString trait? (i.e. not to_string() implemented
|
||||
// separately)
|
||||
&& let Some(expr_def_id) = self.cx.typeck_results().type_dependent_def_id(self.expr.hir_id)
|
||||
&& is_diag_trait_item(self.cx, expr_def_id, sym::ToString)
|
||||
&& self
|
||||
.cx
|
||||
.typeck_results()
|
||||
.type_dependent_def_id(self.expr.hir_id)
|
||||
.opt_parent(self.cx)
|
||||
.is_diag_item(self.cx, sym::ToString)
|
||||
// Is the method is called on self
|
||||
&& let ExprKind::Path(QPath::Resolved(_, path)) = self_arg.kind
|
||||
&& let [segment] = path.segments
|
||||
|
|
@ -210,7 +215,7 @@ impl FormatImplExpr<'_, '_> {
|
|||
// Since the argument to fmt is itself a reference: &self
|
||||
let reference = peel_ref_operators(self.cx, arg);
|
||||
// Is the reference self?
|
||||
if path_to_local(reference).map(|x| self.cx.tcx.hir_name(x)) == Some(kw::SelfLower) {
|
||||
if reference.res_local_id().map(|x| self.cx.tcx.hir_name(x)) == Some(kw::SelfLower) {
|
||||
let FormatTraitNames { name, .. } = self.format_trait_impl;
|
||||
span_lint(
|
||||
self.cx,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::higher;
|
||||
use clippy_utils::ty::is_type_lang_item;
|
||||
use clippy_utils::res::MaybeDef;
|
||||
use rustc_hir::{AssignOpKind, Expr, ExprKind, LangItem, MatchSource};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::declare_lint_pass;
|
||||
|
|
@ -41,7 +41,10 @@ declare_clippy_lint! {
|
|||
declare_lint_pass!(FormatPushString => [FORMAT_PUSH_STRING]);
|
||||
|
||||
fn is_string(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
|
||||
is_type_lang_item(cx, cx.typeck_results().expr_ty(e).peel_refs(), LangItem::String)
|
||||
cx.typeck_results()
|
||||
.expr_ty(e)
|
||||
.peel_refs()
|
||||
.is_lang_item(cx, LangItem::String)
|
||||
}
|
||||
fn is_format(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
|
||||
let e = e.peel_blocks().peel_borrows();
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use clippy_config::Conf;
|
|||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::macros::span_is_local;
|
||||
use clippy_utils::msrvs::{self, Msrv};
|
||||
use clippy_utils::path_def_id;
|
||||
use clippy_utils::res::MaybeResPath;
|
||||
use clippy_utils::source::SpanRangeExt;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::intravisit::{Visitor, walk_path};
|
||||
|
|
@ -90,7 +90,12 @@ impl<'tcx> LateLintPass<'tcx> for FromOverInto {
|
|||
|diag| {
|
||||
// If the target type is likely foreign mention the orphan rules as it's a common source of
|
||||
// confusion
|
||||
if path_def_id(cx, target_ty.peel_refs()).is_none_or(|id| !id.is_local()) {
|
||||
if target_ty
|
||||
.peel_refs()
|
||||
.basic_res()
|
||||
.opt_def_id()
|
||||
.is_none_or(|id| !id.is_local())
|
||||
{
|
||||
diag.help(
|
||||
"`impl From<Local> for Foreign` is allowed by the orphan rules, for more information see\n\
|
||||
https://doc.rust-lang.org/reference/items/implementations.html#trait-implementation-coherence"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use clippy_utils::res::MaybeResPath;
|
||||
use clippy_utils::sym;
|
||||
use clippy_utils::ty::is_c_void;
|
||||
use clippy_utils::{path_def_id, sym};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::{Expr, ExprKind, QPath};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
|
|
@ -41,7 +42,7 @@ impl LateLintPass<'_> for FromRawWithVoidPtr {
|
|||
if let ExprKind::Call(box_from_raw, [arg]) = expr.kind
|
||||
&& let ExprKind::Path(QPath::TypeRelative(ty, seg)) = box_from_raw.kind
|
||||
&& seg.ident.name == sym::from_raw
|
||||
&& let Some(type_str) = path_def_id(cx, ty).and_then(|id| def_id_matches_type(cx, id))
|
||||
&& let Some(type_str) = ty.basic_res().opt_def_id().and_then(|id| def_id_matches_type(cx, id))
|
||||
&& let arg_kind = cx.typeck_results().expr_ty(arg).kind()
|
||||
&& let ty::RawPtr(ty, _) = arg_kind
|
||||
&& is_c_void(cx, *ty)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::res::MaybeDef;
|
||||
use clippy_utils::sugg::Sugg;
|
||||
use clippy_utils::ty::is_type_lang_item;
|
||||
use clippy_utils::{is_in_const_context, is_integer_literal, sym};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, ExprKind, LangItem, PrimTy, QPath, TyKind, def};
|
||||
|
|
@ -89,5 +89,5 @@ impl<'tcx> LateLintPass<'tcx> for FromStrRadix10 {
|
|||
|
||||
/// Checks if a Ty is `String` or `&str`
|
||||
fn is_ty_stringish(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
|
||||
is_type_lang_item(cx, ty, LangItem::String) || ty.peel_refs().is_str()
|
||||
ty.is_lang_item(cx, LangItem::String) || ty.peel_refs().is_str()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@ pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Tr
|
|||
}
|
||||
|
||||
// FIXME: needs to be an EARLY LINT. all attribute lints should be
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
#[expect(clippy::too_many_arguments)]
|
||||
fn check_needless_must_use(
|
||||
cx: &LateContext<'_>,
|
||||
decl: &hir::FnDecl<'_>,
|
||||
|
|
|
|||
|
|
@ -1,12 +1,13 @@
|
|||
use clippy_utils::res::MaybeResPath;
|
||||
use rustc_hir::{self as hir, HirId, HirIdSet, intravisit};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty;
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
|
||||
use clippy_utils::diagnostics::span_lint;
|
||||
use clippy_utils::iter_input_pats;
|
||||
use clippy_utils::ty::is_unsafe_fn;
|
||||
use clippy_utils::visitors::for_each_expr;
|
||||
use clippy_utils::{iter_input_pats, path_to_local};
|
||||
|
||||
use core::ops::ControlFlow;
|
||||
|
||||
|
|
@ -87,7 +88,7 @@ fn raw_ptr_arg(cx: &LateContext<'_>, arg: &hir::Param<'_>) -> Option<HirId> {
|
|||
}
|
||||
|
||||
fn check_arg(cx: &LateContext<'_>, raw_ptrs: &HirIdSet, arg: &hir::Expr<'_>) {
|
||||
if path_to_local(arg).is_some_and(|id| raw_ptrs.contains(&id)) {
|
||||
if arg.res_local_id().is_some_and(|id| raw_ptrs.contains(&id)) {
|
||||
span_lint(
|
||||
cx,
|
||||
NOT_UNSAFE_PTR_ARG_DEREF,
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ fn check_fn_sig<'a>(cx: &LateContext<'a>, decl: &FnDecl<'a>, span: Span, sig: ty
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
#[expect(clippy::too_many_arguments)]
|
||||
pub(crate) fn check_fn<'a>(
|
||||
cx: &LateContext<'a>,
|
||||
kind: FnKind<'a>,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use clippy_utils::msrvs::{self, Msrv};
|
||||
use clippy_utils::res::MaybeDef;
|
||||
use rustc_errors::Diag;
|
||||
use rustc_hir as hir;
|
||||
use rustc_lint::{LateContext, LintContext};
|
||||
|
|
@ -6,7 +7,7 @@ use rustc_middle::ty::{self, Ty};
|
|||
use rustc_span::{Span, sym};
|
||||
|
||||
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then};
|
||||
use clippy_utils::ty::{AdtVariantInfo, approx_ty_size, is_type_diagnostic_item};
|
||||
use clippy_utils::ty::{AdtVariantInfo, approx_ty_size};
|
||||
use clippy_utils::{is_no_std_crate, trait_ref_of_method};
|
||||
|
||||
use super::{RESULT_LARGE_ERR, RESULT_UNIT_ERR};
|
||||
|
|
@ -24,7 +25,7 @@ fn result_err_ty<'tcx>(
|
|||
&& let ty = cx
|
||||
.tcx
|
||||
.instantiate_bound_regions_with_erased(cx.tcx.fn_sig(id).instantiate_identity().output())
|
||||
&& is_type_diagnostic_item(cx, ty, sym::Result)
|
||||
&& ty.is_diag_item(cx, sym::Result)
|
||||
&& let ty::Adt(_, args) = ty.kind()
|
||||
{
|
||||
let err_ty = args.type_at(1);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::res::MaybeDef;
|
||||
use clippy_utils::visitors::for_each_expr_without_closures;
|
||||
use clippy_utils::{eq_expr_value, higher, sym};
|
||||
use core::ops::ControlFlow;
|
||||
|
|
@ -95,7 +95,7 @@ fn mutex_lock_call<'tcx>(
|
|||
if let ExprKind::MethodCall(path, self_arg, [], _) = &expr.kind
|
||||
&& path.ident.name == sym::lock
|
||||
&& let ty = cx.typeck_results().expr_ty(self_arg).peel_refs()
|
||||
&& is_type_diagnostic_item(cx, ty, sym::Mutex)
|
||||
&& ty.is_diag_item(cx, sym::Mutex)
|
||||
&& op_mutex.is_none_or(|op| eq_expr_value(cx, self_arg, op))
|
||||
{
|
||||
ControlFlow::Break(self_arg)
|
||||
|
|
|
|||
|
|
@ -2,11 +2,11 @@ use clippy_config::Conf;
|
|||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::eager_or_lazy::switch_to_eager_eval;
|
||||
use clippy_utils::msrvs::{self, Msrv};
|
||||
use clippy_utils::res::{MaybeDef, MaybeQPath};
|
||||
use clippy_utils::source::{snippet_with_applicability, snippet_with_context, walk_span_to_context};
|
||||
use clippy_utils::sugg::Sugg;
|
||||
use clippy_utils::{
|
||||
contains_return, expr_adjustment_requires_coercion, higher, is_else_clause, is_in_const_context, is_res_lang_ctor,
|
||||
path_res, peel_blocks, sym,
|
||||
contains_return, expr_adjustment_requires_coercion, higher, is_else_clause, is_in_const_context, peel_blocks, sym,
|
||||
};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::LangItem::{OptionNone, OptionSome};
|
||||
|
|
@ -73,8 +73,8 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone {
|
|||
&& let ExprKind::Call(then_call, [then_arg]) = then_expr.kind
|
||||
&& !expr.span.from_expansion()
|
||||
&& !then_expr.span.from_expansion()
|
||||
&& is_res_lang_ctor(cx, path_res(cx, then_call), OptionSome)
|
||||
&& is_res_lang_ctor(cx, path_res(cx, peel_blocks(els)), OptionNone)
|
||||
&& then_call.res(cx).ctor_parent(cx).is_lang_item(cx, OptionSome)
|
||||
&& peel_blocks(els).res(cx).ctor_parent(cx).is_lang_item(cx, OptionNone)
|
||||
&& !is_else_clause(cx.tcx, expr)
|
||||
&& !is_in_const_context(cx)
|
||||
&& self.msrv.meets(cx, msrvs::BOOL_THEN)
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::res::MaybeResPath;
|
||||
use clippy_utils::source::{IntoSpan, SpanRangeExt, first_line_of_span, indent_of, reindent_multiline, snippet};
|
||||
use clippy_utils::ty::needs_ordered_drop;
|
||||
use clippy_utils::visitors::for_each_expr_without_closures;
|
||||
use clippy_utils::{
|
||||
ContainsName, HirEqInterExpr, SpanlessEq, capture_local_usage, get_enclosing_block, hash_expr, hash_stmt,
|
||||
path_to_local,
|
||||
};
|
||||
use core::iter;
|
||||
use core::ops::ControlFlow;
|
||||
|
|
@ -149,7 +149,7 @@ fn eq_binding_names(s: &Stmt<'_>, names: &[(HirId, Symbol)]) -> bool {
|
|||
/// Checks if the statement modifies or moves any of the given locals.
|
||||
fn modifies_any_local<'tcx>(cx: &LateContext<'tcx>, s: &'tcx Stmt<'_>, locals: &HirIdSet) -> bool {
|
||||
for_each_expr_without_closures(s, |e| {
|
||||
if let Some(id) = path_to_local(e)
|
||||
if let Some(id) = e.res_local_id()
|
||||
&& locals.contains(&id)
|
||||
&& !capture_local_usage(cx, e).is_imm_ref()
|
||||
{
|
||||
|
|
@ -198,7 +198,7 @@ fn scan_block_for_eq<'tcx>(
|
|||
let mut cond_locals = HirIdSet::default();
|
||||
for &cond in conds {
|
||||
let _: Option<!> = for_each_expr_without_closures(cond, |e| {
|
||||
if let Some(id) = path_to_local(e) {
|
||||
if let Some(id) = e.res_local_id() {
|
||||
cond_locals.insert(id);
|
||||
}
|
||||
ControlFlow::Continue(())
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use clippy_utils::diagnostics::span_lint;
|
||||
use clippy_utils::res::MaybeResPath;
|
||||
use clippy_utils::ty::InteriorMut;
|
||||
use clippy_utils::{SpanlessEq, eq_expr_value, find_binding_init, hash_expr, path_to_local, search_same};
|
||||
use clippy_utils::{SpanlessEq, eq_expr_value, find_binding_init, hash_expr, search_same};
|
||||
use rustc_hir::{Expr, ExprKind};
|
||||
use rustc_lint::LateContext;
|
||||
|
||||
|
|
@ -16,7 +17,7 @@ fn method_caller_is_mutable<'tcx>(
|
|||
interior_mut.is_interior_mut_ty(cx, caller_ty)
|
||||
|| caller_ty.is_mutable_ptr()
|
||||
// `find_binding_init` will return the binding iff its not mutable
|
||||
|| path_to_local(caller_expr)
|
||||
|| caller_expr.res_local_id()
|
||||
.and_then(|hid| find_binding_init(cx, hid))
|
||||
.is_none()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use std::borrow::Cow;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use clippy_utils::res::MaybeDef;
|
||||
use rustc_errors::{Applicability, Diag};
|
||||
use rustc_hir::intravisit::{Visitor, VisitorExt, walk_body, walk_expr, walk_ty};
|
||||
use rustc_hir::{self as hir, AmbigArg, Body, Expr, ExprKind, GenericArg, Item, ItemKind, QPath, TyKind};
|
||||
|
|
@ -14,7 +15,6 @@ use rustc_span::Span;
|
|||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::source::{IntoSpan, SpanRangeExt, snippet};
|
||||
use clippy_utils::sym;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
|
|
@ -227,14 +227,14 @@ impl<'tcx> ImplicitHasherType<'tcx> {
|
|||
|
||||
let ty = lower_ty(cx.tcx, hir_ty);
|
||||
|
||||
if is_type_diagnostic_item(cx, ty, sym::HashMap) && params_len == 2 {
|
||||
if ty.is_diag_item(cx, sym::HashMap) && params_len == 2 {
|
||||
Some(ImplicitHasherType::HashMap(
|
||||
hir_ty.span,
|
||||
ty,
|
||||
snippet(cx, params[0].span, "K"),
|
||||
snippet(cx, params[1].span, "V"),
|
||||
))
|
||||
} else if is_type_diagnostic_item(cx, ty, sym::HashSet) && params_len == 1 {
|
||||
} else if ty.is_diag_item(cx, sym::HashSet) && params_len == 1 {
|
||||
Some(ImplicitHasherType::HashSet(
|
||||
hir_ty.span,
|
||||
ty,
|
||||
|
|
|
|||
|
|
@ -112,7 +112,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
#[expect(clippy::too_many_arguments)]
|
||||
fn check_manual_check<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
expr: &Expr<'tcx>,
|
||||
|
|
@ -165,7 +165,7 @@ fn check_manual_check<'tcx>(
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
#[expect(clippy::too_many_arguments)]
|
||||
fn check_gt(
|
||||
cx: &LateContext<'_>,
|
||||
condition_span: Span,
|
||||
|
|
@ -196,7 +196,7 @@ fn is_side_effect_free(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
|
|||
eq_expr_value(cx, expr, expr)
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
#[expect(clippy::too_many_arguments)]
|
||||
fn check_subtraction(
|
||||
cx: &LateContext<'_>,
|
||||
condition_span: Span,
|
||||
|
|
|
|||
|
|
@ -2,9 +2,10 @@ use clippy_config::Conf;
|
|||
use clippy_utils::consts::{ConstEvalCtxt, Constant};
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::higher::IfLet;
|
||||
use clippy_utils::is_lint_allowed;
|
||||
use clippy_utils::msrvs::{self, Msrv};
|
||||
use clippy_utils::res::MaybeResPath;
|
||||
use clippy_utils::ty::is_copy;
|
||||
use clippy_utils::{is_lint_allowed, path_to_local};
|
||||
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
|
|
@ -225,7 +226,7 @@ impl<'tcx> Visitor<'tcx> for SliceIndexLintingVisitor<'_, 'tcx> {
|
|||
}
|
||||
|
||||
fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
|
||||
if let Some(local_id) = path_to_local(expr) {
|
||||
if let Some(local_id) = expr.res_local_id() {
|
||||
let Self {
|
||||
cx,
|
||||
ref mut slice_lint_info,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::res::MaybeDef;
|
||||
use clippy_utils::source::SpanRangeExt;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::{peel_blocks, peel_hir_expr_while, sym};
|
||||
use rustc_ast::LitKind;
|
||||
use rustc_errors::Applicability;
|
||||
|
|
@ -47,7 +47,11 @@ impl<'tcx> LateLintPass<'tcx> for IneffectiveOpenOptions {
|
|||
if let ExprKind::MethodCall(name, recv, [_], _) = expr.kind
|
||||
&& name.ident.name == sym::open
|
||||
&& !expr.span.from_expansion()
|
||||
&& is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv).peel_refs(), sym::FsOpenOptions)
|
||||
&& cx
|
||||
.typeck_results()
|
||||
.expr_ty(recv)
|
||||
.peel_refs()
|
||||
.is_diag_item(cx, sym::FsOpenOptions)
|
||||
{
|
||||
let mut append = false;
|
||||
let mut write = None;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use clippy_utils::diagnostics::span_lint;
|
||||
use clippy_utils::ty::{get_type_diagnostic_name, implements_trait};
|
||||
use clippy_utils::res::MaybeDef;
|
||||
use clippy_utils::ty::implements_trait;
|
||||
use clippy_utils::{higher, sym};
|
||||
use rustc_hir::{BorrowKind, Closure, Expr, ExprKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
|
|
@ -235,7 +236,7 @@ fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
|
|||
} else if method.ident.name == sym::collect {
|
||||
let ty = cx.typeck_results().expr_ty(expr);
|
||||
if matches!(
|
||||
get_type_diagnostic_name(cx, ty),
|
||||
ty.opt_diag_name(cx),
|
||||
Some(
|
||||
sym::BinaryHeap
|
||||
| sym::BTreeMap
|
||||
|
|
|
|||
|
|
@ -1,17 +1,23 @@
|
|||
use clippy_config::Conf;
|
||||
use clippy_config::types::InherentImplLintScope;
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::is_lint_allowed;
|
||||
use clippy_utils::fulfill_or_allowed;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_hir::def_id::{LocalDefId, LocalModDefId};
|
||||
use rustc_hir::{Item, ItemKind, Node};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::declare_lint_pass;
|
||||
use rustc_span::Span;
|
||||
use rustc_session::impl_lint_pass;
|
||||
use rustc_span::{FileName, Span};
|
||||
use std::collections::hash_map::Entry;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks for multiple inherent implementations of a struct
|
||||
///
|
||||
/// The config option controls the scope in which multiple inherent `impl` blocks for the same
|
||||
/// struct are linted, allowing values of `module` (only within the same module), `file`
|
||||
/// (within the same file), or `crate` (anywhere in the crate, default).
|
||||
///
|
||||
/// ### Why restrict this?
|
||||
/// Splitting the implementation of a type makes the code harder to navigate.
|
||||
///
|
||||
|
|
@ -41,7 +47,26 @@ declare_clippy_lint! {
|
|||
"Multiple inherent impl that could be grouped"
|
||||
}
|
||||
|
||||
declare_lint_pass!(MultipleInherentImpl => [MULTIPLE_INHERENT_IMPL]);
|
||||
impl_lint_pass!(MultipleInherentImpl => [MULTIPLE_INHERENT_IMPL]);
|
||||
|
||||
pub struct MultipleInherentImpl {
|
||||
scope: InherentImplLintScope,
|
||||
}
|
||||
|
||||
impl MultipleInherentImpl {
|
||||
pub fn new(conf: &'static Conf) -> Self {
|
||||
Self {
|
||||
scope: conf.inherent_impl_lint_scope,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Hash, Eq, PartialEq, Clone)]
|
||||
enum Criterion {
|
||||
Module(LocalModDefId),
|
||||
File(FileName),
|
||||
Crate,
|
||||
}
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for MultipleInherentImpl {
|
||||
fn check_crate_post(&mut self, cx: &LateContext<'tcx>) {
|
||||
|
|
@ -55,18 +80,27 @@ impl<'tcx> LateLintPass<'tcx> for MultipleInherentImpl {
|
|||
|
||||
for (&id, impl_ids) in &impls.inherent_impls {
|
||||
if impl_ids.len() < 2
|
||||
// Check for `#[allow]` on the type definition
|
||||
|| is_lint_allowed(
|
||||
// Check for `#[expect]` or `#[allow]` on the type definition
|
||||
|| fulfill_or_allowed(
|
||||
cx,
|
||||
MULTIPLE_INHERENT_IMPL,
|
||||
cx.tcx.local_def_id_to_hir_id(id),
|
||||
[cx.tcx.local_def_id_to_hir_id(id)],
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for impl_id in impl_ids.iter().map(|id| id.expect_local()) {
|
||||
let impl_ty = cx.tcx.type_of(impl_id).instantiate_identity();
|
||||
match type_map.entry(impl_ty) {
|
||||
let hir_id = cx.tcx.local_def_id_to_hir_id(impl_id);
|
||||
let criterion = match self.scope {
|
||||
InherentImplLintScope::Module => Criterion::Module(cx.tcx.parent_module(hir_id)),
|
||||
InherentImplLintScope::File => {
|
||||
let span = cx.tcx.hir_span(hir_id);
|
||||
Criterion::File(cx.tcx.sess.source_map().lookup_source_file(span.lo()).name.clone())
|
||||
},
|
||||
InherentImplLintScope::Crate => Criterion::Crate,
|
||||
};
|
||||
match type_map.entry((impl_ty, criterion)) {
|
||||
Entry::Vacant(e) => {
|
||||
// Store the id for the first impl block of this type. The span is retrieved lazily.
|
||||
e.insert(IdOrSpan::Id(impl_id));
|
||||
|
|
@ -97,7 +131,6 @@ impl<'tcx> LateLintPass<'tcx> for MultipleInherentImpl {
|
|||
// Switching to the next type definition, no need to keep the current entries around.
|
||||
type_map.clear();
|
||||
}
|
||||
|
||||
// `TyCtxt::crate_inherent_impls` doesn't have a defined order. Sort the lint output first.
|
||||
lint_spans.sort_by_key(|x| x.0.lo());
|
||||
for (span, first_span) in lint_spans {
|
||||
|
|
@ -125,7 +158,7 @@ fn get_impl_span(cx: &LateContext<'_>, id: LocalDefId) -> Option<Span> {
|
|||
{
|
||||
(!span.from_expansion()
|
||||
&& impl_item.generics.params.is_empty()
|
||||
&& !is_lint_allowed(cx, MULTIPLE_INHERENT_IMPL, id))
|
||||
&& !fulfill_or_allowed(cx, MULTIPLE_INHERENT_IMPL, [id]))
|
||||
.then_some(span)
|
||||
} else {
|
||||
None
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use clippy_utils::ty::{implements_trait, is_type_lang_item};
|
||||
use clippy_utils::res::MaybeDef;
|
||||
use clippy_utils::ty::implements_trait;
|
||||
use clippy_utils::{return_ty, trait_ref_of_method};
|
||||
use rustc_abi::ExternAbi;
|
||||
use rustc_hir::{GenericParamKind, ImplItem, ImplItemKind, LangItem};
|
||||
|
|
@ -104,7 +105,7 @@ impl<'tcx> LateLintPass<'tcx> for InherentToString {
|
|||
&& impl_item.generics.params.iter().all(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }))
|
||||
&& !impl_item.span.from_expansion()
|
||||
// Check if return type is String
|
||||
&& is_type_lang_item(cx, return_ty(cx, impl_item.owner_id), LangItem::String)
|
||||
&& return_ty(cx, impl_item.owner_id).is_lang_item(cx, LangItem::String)
|
||||
// Filters instances of to_string which are required by a trait
|
||||
&& trait_ref_of_method(cx, impl_item.owner_id).is_none()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use clippy_utils::diagnostics::span_lint;
|
||||
use clippy_utils::higher::ForLoop;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::res::MaybeDef;
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::declare_lint_pass;
|
||||
use rustc_span::sym;
|
||||
|
|
@ -55,9 +55,7 @@ impl LateLintPass<'_> for IterOverHashType {
|
|||
if let Some(for_loop) = ForLoop::hir(expr)
|
||||
&& !for_loop.body.span.from_expansion()
|
||||
&& let ty = cx.typeck_results().expr_ty(for_loop.arg).peel_refs()
|
||||
&& hash_iter_tys
|
||||
.into_iter()
|
||||
.any(|sym| is_type_diagnostic_item(cx, ty, sym))
|
||||
&& hash_iter_tys.into_iter().any(|sym| ty.is_diag_item(cx, sym))
|
||||
{
|
||||
span_lint(
|
||||
cx,
|
||||
|
|
|
|||
|
|
@ -113,35 +113,18 @@ impl<'tcx> LateLintPass<'tcx> for LegacyNumericConstants {
|
|||
// since this would only require removing a `use` import (which is already linted).
|
||||
&& !is_numeric_const_path_canonical(path, [*mod_name, *name])
|
||||
{
|
||||
(
|
||||
vec![(expr.span, format!("{mod_name}::{name}"))],
|
||||
"usage of a legacy numeric constant",
|
||||
)
|
||||
(format!("{mod_name}::{name}"), "usage of a legacy numeric constant")
|
||||
// `<integer>::xxx_value` check
|
||||
} else if let ExprKind::Call(func, []) = &expr.kind
|
||||
&& let ExprKind::Path(qpath) = &func.kind
|
||||
&& let QPath::TypeRelative(ty, last_segment) = qpath
|
||||
&& let Some(def_id) = cx.qpath_res(qpath, func.hir_id).opt_def_id()
|
||||
&& is_integer_method(cx, def_id)
|
||||
&& let Some(mod_name) = ty.span.get_source_text(cx)
|
||||
&& ty.span.eq_ctxt(last_segment.ident.span)
|
||||
{
|
||||
let mut sugg = vec![
|
||||
// Replace the function name up to the end by the constant name
|
||||
(
|
||||
last_segment.ident.span.to(expr.span.shrink_to_hi()),
|
||||
last_segment.ident.name.as_str()[..=2].to_ascii_uppercase(),
|
||||
),
|
||||
];
|
||||
let before_span = expr.span.shrink_to_lo().until(ty.span);
|
||||
if !before_span.is_empty() {
|
||||
// Remove everything before the type name
|
||||
sugg.push((before_span, String::new()));
|
||||
}
|
||||
// Use `::` between the type name and the constant
|
||||
let between_span = ty.span.shrink_to_hi().until(last_segment.ident.span);
|
||||
if !between_span.check_source_text(cx, |s| s == "::") {
|
||||
sugg.push((between_span, String::from("::")));
|
||||
}
|
||||
(sugg, "usage of a legacy numeric method")
|
||||
let name = last_segment.ident.name.as_str()[..=2].to_ascii_uppercase();
|
||||
(format!("{mod_name}::{name}"), "usage of a legacy numeric method")
|
||||
} else {
|
||||
return;
|
||||
};
|
||||
|
|
@ -151,7 +134,8 @@ impl<'tcx> LateLintPass<'tcx> for LegacyNumericConstants {
|
|||
&& !is_from_proc_macro(cx, expr)
|
||||
{
|
||||
span_lint_and_then(cx, LEGACY_NUMERIC_CONSTANTS, expr.span, msg, |diag| {
|
||||
diag.multipart_suggestion_verbose(
|
||||
diag.span_suggestion_verbose(
|
||||
expr.span,
|
||||
"use the associated constant instead",
|
||||
sugg,
|
||||
Applicability::MaybeIncorrect,
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
|
||||
use clippy_utils::res::{MaybeDef, MaybeTypeckRes};
|
||||
use clippy_utils::source::{SpanRangeExt, snippet_with_context};
|
||||
use clippy_utils::sugg::{Sugg, has_enclosing_paren};
|
||||
use clippy_utils::ty::implements_trait;
|
||||
use clippy_utils::{
|
||||
fulfill_or_allowed, get_parent_as_impl, is_trait_method, parent_item_name, peel_ref_operators, sym,
|
||||
};
|
||||
use clippy_utils::{fulfill_or_allowed, get_parent_as_impl, parent_item_name, peel_ref_operators, sym};
|
||||
use rustc_ast::ast::LitKind;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::def::Res;
|
||||
|
|
@ -204,7 +203,7 @@ impl<'tcx> LateLintPass<'tcx> for LenZero {
|
|||
}
|
||||
|
||||
if let ExprKind::MethodCall(method, lhs_expr, [rhs_expr], _) = expr.kind
|
||||
&& is_trait_method(cx, expr, sym::PartialEq)
|
||||
&& cx.ty_based_def(expr).opt_parent(cx).is_diag_item(cx, sym::PartialEq)
|
||||
&& !expr.span.from_expansion()
|
||||
{
|
||||
check_empty_expr(
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use clippy_utils::diagnostics::span_lint_hir_and_then;
|
||||
use clippy_utils::path_to_local_id;
|
||||
use clippy_utils::res::MaybeResPath;
|
||||
use clippy_utils::source::snippet;
|
||||
use clippy_utils::visitors::is_local_used;
|
||||
use rustc_errors::Applicability;
|
||||
|
|
@ -145,7 +145,7 @@ fn check_assign<'tcx>(
|
|||
&& let Some(expr) = block.stmts.iter().last()
|
||||
&& let hir::StmtKind::Semi(expr) = expr.kind
|
||||
&& let hir::ExprKind::Assign(var, value, _) = expr.kind
|
||||
&& path_to_local_id(var, decl)
|
||||
&& var.res_local_id() == Some(decl)
|
||||
{
|
||||
if block
|
||||
.stmts
|
||||
|
|
|
|||
|
|
@ -318,6 +318,7 @@ mod ref_patterns;
|
|||
mod reference;
|
||||
mod regex;
|
||||
mod repeat_vec_with_capacity;
|
||||
mod replace_box;
|
||||
mod reserve_after_initialization;
|
||||
mod return_self_not_must_use;
|
||||
mod returns;
|
||||
|
|
@ -394,6 +395,7 @@ mod useless_conversion;
|
|||
mod vec;
|
||||
mod vec_init_then_push;
|
||||
mod visibility;
|
||||
mod volatile_composites;
|
||||
mod wildcard_imports;
|
||||
mod write;
|
||||
mod zero_div_zero;
|
||||
|
|
@ -581,7 +583,7 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co
|
|||
store.register_early_pass(|| Box::new(suspicious_operation_groupings::SuspiciousOperationGroupings));
|
||||
store.register_late_pass(|_| Box::new(suspicious_trait_impl::SuspiciousImpl));
|
||||
store.register_late_pass(|_| Box::new(map_unit_fn::MapUnit));
|
||||
store.register_late_pass(|_| Box::new(inherent_impl::MultipleInherentImpl));
|
||||
store.register_late_pass(move |_| Box::new(inherent_impl::MultipleInherentImpl::new(conf)));
|
||||
store.register_late_pass(|_| Box::new(neg_cmp_op_on_partial_ord::NoNegCompOpForPartialOrd));
|
||||
store.register_late_pass(move |_| Box::new(unwrap::Unwrap::new(conf)));
|
||||
store.register_late_pass(move |_| Box::new(indexing_slicing::IndexingSlicing::new(conf)));
|
||||
|
|
@ -612,7 +614,7 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co
|
|||
store.register_late_pass(|_| Box::new(items_after_statements::ItemsAfterStatements));
|
||||
store.register_early_pass(|| Box::new(precedence::Precedence));
|
||||
store.register_late_pass(|_| Box::new(needless_parens_on_range_literals::NeedlessParensOnRangeLiterals));
|
||||
store.register_early_pass(|| Box::new(needless_continue::NeedlessContinue));
|
||||
store.register_late_pass(|_| Box::new(needless_continue::NeedlessContinue));
|
||||
store.register_early_pass(|| Box::new(redundant_else::RedundantElse));
|
||||
store.register_late_pass(|_| Box::new(create_dir::CreateDir));
|
||||
store.register_early_pass(|| Box::new(needless_arbitrary_self_type::NeedlessArbitrarySelfType));
|
||||
|
|
@ -758,7 +760,7 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co
|
|||
store.register_late_pass(move |_| Box::new(large_stack_frames::LargeStackFrames::new(conf)));
|
||||
store.register_late_pass(|_| Box::new(single_range_in_vec_init::SingleRangeInVecInit));
|
||||
store.register_late_pass(move |_| Box::new(needless_pass_by_ref_mut::NeedlessPassByRefMut::new(conf)));
|
||||
store.register_late_pass(|_| Box::new(non_canonical_impls::NonCanonicalImpls));
|
||||
store.register_late_pass(|tcx| Box::new(non_canonical_impls::NonCanonicalImpls::new(tcx)));
|
||||
store.register_late_pass(move |_| Box::new(single_call_fn::SingleCallFn::new(conf)));
|
||||
store.register_early_pass(move || Box::new(raw_strings::RawStrings::new(conf)));
|
||||
store.register_late_pass(move |_| Box::new(legacy_numeric_constants::LegacyNumericConstants::new(conf)));
|
||||
|
|
@ -825,5 +827,7 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co
|
|||
store.register_late_pass(|_| Box::new(infallible_try_from::InfallibleTryFrom));
|
||||
store.register_late_pass(|_| Box::new(coerce_container_to_any::CoerceContainerToAny));
|
||||
store.register_late_pass(|_| Box::new(toplevel_ref_arg::ToplevelRefArg));
|
||||
store.register_late_pass(|_| Box::new(volatile_composites::VolatileComposites));
|
||||
store.register_late_pass(|_| Box::new(replace_box::ReplaceBox));
|
||||
// add lints here, do not remove this comment, it's used in `new_lint`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -184,7 +184,7 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
#[expect(clippy::too_many_arguments)]
|
||||
fn check_fn_inner<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
sig: &'tcx FnSig<'_>,
|
||||
|
|
@ -540,7 +540,7 @@ fn has_where_lifetimes<'tcx>(cx: &LateContext<'tcx>, generics: &'tcx Generics<'_
|
|||
false
|
||||
}
|
||||
|
||||
#[allow(clippy::struct_excessive_bools)]
|
||||
#[expect(clippy::struct_excessive_bools)]
|
||||
struct Usage {
|
||||
lifetime: Lifetime,
|
||||
in_where_predicate: bool,
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::msrvs::{self, Msrv};
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::{is_diag_item_method, is_trait_method, path_to_local_id, sym};
|
||||
use clippy_utils::res::{MaybeDef, MaybeResPath, MaybeTypeckRes};
|
||||
use clippy_utils::sym;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Body, Closure, Expr, ExprKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
|
|
@ -73,10 +73,13 @@ impl_lint_pass!(LinesFilterMapOk => [LINES_FILTER_MAP_OK]);
|
|||
impl LateLintPass<'_> for LinesFilterMapOk {
|
||||
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||
if let ExprKind::MethodCall(fm_method, fm_receiver, fm_args, fm_span) = expr.kind
|
||||
&& is_trait_method(cx, expr, sym::Iterator)
|
||||
&& cx.ty_based_def(expr).opt_parent(cx).is_diag_item(cx, sym::Iterator)
|
||||
&& let fm_method_name = fm_method.ident.name
|
||||
&& matches!(fm_method_name, sym::filter_map | sym::flat_map | sym::flatten)
|
||||
&& is_type_diagnostic_item(cx, cx.typeck_results().expr_ty_adjusted(fm_receiver), sym::IoLines)
|
||||
&& cx
|
||||
.typeck_results()
|
||||
.expr_ty_adjusted(fm_receiver)
|
||||
.is_diag_item(cx, sym::IoLines)
|
||||
&& should_lint(cx, fm_args, fm_method_name)
|
||||
&& self.msrv.meets(cx, msrvs::MAP_WHILE)
|
||||
{
|
||||
|
|
@ -117,10 +120,15 @@ fn should_lint(cx: &LateContext<'_>, args: &[Expr<'_>], method_name: Symbol) ->
|
|||
params: [param], value, ..
|
||||
} = cx.tcx.hir_body(*body)
|
||||
&& let ExprKind::MethodCall(method, receiver, [], _) = value.kind
|
||||
&& path_to_local_id(receiver, param.pat.hir_id)
|
||||
&& let Some(method_did) = cx.typeck_results().type_dependent_def_id(value.hir_id)
|
||||
{
|
||||
is_diag_item_method(cx, method_did, sym::Result) && method.ident.name == sym::ok
|
||||
method.ident.name == sym::ok
|
||||
&& receiver.res_local_id() == Some(param.pat.hir_id)
|
||||
&& cx
|
||||
.typeck_results()
|
||||
.type_dependent_def_id(value.hir_id)
|
||||
.opt_parent(cx)
|
||||
.opt_impl_ty(cx)
|
||||
.is_diag_item(cx, sym::Result)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
use std::ops::ControlFlow;
|
||||
|
||||
use clippy_utils::diagnostics::span_lint_hir_and_then;
|
||||
use clippy_utils::ty::is_type_lang_item;
|
||||
use clippy_utils::res::{MaybeDef, MaybeResPath};
|
||||
use clippy_utils::visitors::for_each_expr;
|
||||
use clippy_utils::{eq_expr_value, higher, path_to_local_id, sym};
|
||||
use clippy_utils::{eq_expr_value, higher, sym};
|
||||
use rustc_errors::{Applicability, MultiSpan};
|
||||
use rustc_hir::{Expr, ExprKind, LangItem, Node, Pat, PatKind};
|
||||
use rustc_lint::LateContext;
|
||||
|
|
@ -49,7 +49,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'_>, iterable: &Expr
|
|||
{
|
||||
// Destructured iterator element `(idx, _)`, look for uses of the binding
|
||||
for_each_expr(cx, body, |expr| {
|
||||
if path_to_local_id(expr, binding_id) {
|
||||
if expr.res_local_id() == Some(binding_id) {
|
||||
check_index_usage(cx, expr, pat, enumerate_span, chars_span, chars_recv);
|
||||
}
|
||||
CONTINUE
|
||||
|
|
@ -58,7 +58,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'_>, iterable: &Expr
|
|||
// Bound as a tuple, look for `tup.0`
|
||||
for_each_expr(cx, body, |expr| {
|
||||
if let ExprKind::Field(e, field) = expr.kind
|
||||
&& path_to_local_id(e, binding_id)
|
||||
&& e.res_local_id() == Some(binding_id)
|
||||
&& field.name == sym::integer(0)
|
||||
{
|
||||
check_index_usage(cx, expr, pat, enumerate_span, chars_span, chars_recv);
|
||||
|
|
@ -81,7 +81,7 @@ fn check_index_usage<'tcx>(
|
|||
return;
|
||||
};
|
||||
|
||||
let is_string_like = |ty: Ty<'_>| ty.is_str() || is_type_lang_item(cx, ty, LangItem::String);
|
||||
let is_string_like = |ty: Ty<'_>| ty.is_str() || ty.is_lang_item(cx, LangItem::String);
|
||||
let message = match parent_expr.kind {
|
||||
ExprKind::MethodCall(segment, recv, ..)
|
||||
// We currently only lint `str` methods (which `String` can deref to), so a `.is_str()` check is sufficient here
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use super::EXPLICIT_INTO_ITER_LOOP;
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::is_trait_method;
|
||||
use clippy_utils::res::{MaybeDef, MaybeTypeckRes};
|
||||
use clippy_utils::source::snippet_with_context;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::Expr;
|
||||
|
|
@ -43,7 +43,11 @@ impl AdjustKind {
|
|||
}
|
||||
|
||||
pub(super) fn check(cx: &LateContext<'_>, self_arg: &Expr<'_>, call_expr: &Expr<'_>) {
|
||||
if !is_trait_method(cx, call_expr, sym::IntoIterator) {
|
||||
if !cx
|
||||
.ty_based_def(call_expr)
|
||||
.opt_parent(cx)
|
||||
.is_diag_item(cx, sym::IntoIterator)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
use super::EXPLICIT_ITER_LOOP;
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::msrvs::{self, Msrv};
|
||||
use clippy_utils::res::MaybeDef;
|
||||
use clippy_utils::source::snippet_with_context;
|
||||
use clippy_utils::sym;
|
||||
use clippy_utils::ty::{
|
||||
implements_trait, implements_trait_with_env, is_copy, is_type_lang_item, make_normalized_projection,
|
||||
implements_trait, implements_trait_with_env, is_copy, make_normalized_projection,
|
||||
make_normalized_projection_with_regions, normalize_with_regions,
|
||||
};
|
||||
use rustc_errors::Applicability;
|
||||
|
|
@ -127,8 +128,7 @@ fn is_ref_iterable<'tcx>(
|
|||
let self_ty = typeck.expr_ty(self_arg);
|
||||
let self_is_copy = is_copy(cx, self_ty);
|
||||
|
||||
if is_type_lang_item(cx, self_ty.peel_refs(), rustc_hir::LangItem::OwnedBox)
|
||||
&& !msrv.meets(cx, msrvs::BOX_INTO_ITER)
|
||||
if self_ty.peel_refs().is_lang_item(cx, rustc_hir::LangItem::OwnedBox) && !msrv.meets(cx, msrvs::BOX_INTO_ITER)
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use super::FOR_KV_MAP;
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::res::MaybeDef;
|
||||
use clippy_utils::source::snippet;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::{pat_is_wild, sugg};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, Pat, PatKind};
|
||||
|
|
@ -34,7 +34,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, arg: &'tcx
|
|||
_ => arg,
|
||||
};
|
||||
|
||||
if is_type_diagnostic_item(cx, ty, sym::HashMap) || is_type_diagnostic_item(cx, ty, sym::BTreeMap) {
|
||||
if ty.is_diag_item(cx, sym::HashMap) || ty.is_diag_item(cx, sym::BTreeMap) {
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
FOR_KV_MAP,
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
use super::ITER_NEXT_LOOP;
|
||||
use clippy_utils::diagnostics::span_lint;
|
||||
use clippy_utils::is_trait_method;
|
||||
use clippy_utils::res::{MaybeDef, MaybeTypeckRes};
|
||||
use rustc_hir::Expr;
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_span::sym;
|
||||
|
||||
pub(super) fn check(cx: &LateContext<'_>, arg: &Expr<'_>) {
|
||||
if is_trait_method(cx, arg, sym::Iterator) {
|
||||
if cx.ty_based_def(arg).opt_parent(cx).is_diag_item(cx, sym::Iterator) {
|
||||
span_lint(
|
||||
cx,
|
||||
ITER_NEXT_LOOP,
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
use super::MANUAL_FIND;
|
||||
use super::utils::make_iterator_snippet;
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::res::{MaybeDef, MaybeQPath, MaybeResPath};
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::ty::implements_trait;
|
||||
use clippy_utils::usage::contains_return_break_continue_macro;
|
||||
use clippy_utils::{higher, is_res_lang_ctor, path_res, peel_blocks_with_stmt};
|
||||
use clippy_utils::{higher, peel_blocks_with_stmt};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_hir::{BindingMode, Block, Expr, ExprKind, HirId, Node, Pat, PatKind, Stmt, StmtKind};
|
||||
use rustc_lint::LateContext;
|
||||
|
|
@ -34,8 +34,8 @@ pub(super) fn check<'tcx>(
|
|||
&& let StmtKind::Semi(semi) = stmt.kind
|
||||
&& let ExprKind::Ret(Some(ret_value)) = semi.kind
|
||||
&& let ExprKind::Call(ctor, [inner_ret]) = ret_value.kind
|
||||
&& is_res_lang_ctor(cx, path_res(cx, ctor), LangItem::OptionSome)
|
||||
&& path_res(cx, inner_ret) == Res::Local(binding_id)
|
||||
&& ctor.res(cx).ctor_parent(cx).is_lang_item(cx, LangItem::OptionSome)
|
||||
&& inner_ret.res_local_id() == Some(binding_id)
|
||||
&& !contains_return_break_continue_macro(cond)
|
||||
&& let Some((last_stmt, last_ret)) = last_stmt_and_ret(cx, expr)
|
||||
{
|
||||
|
|
@ -150,7 +150,7 @@ fn last_stmt_and_ret<'tcx>(
|
|||
&& let Some((_, Node::Block(block))) = parent_iter.next()
|
||||
&& let Some((last_stmt, last_ret)) = extract(block)
|
||||
&& last_stmt.hir_id == node_hir
|
||||
&& is_res_lang_ctor(cx, path_res(cx, last_ret), LangItem::OptionNone)
|
||||
&& last_ret.res(cx).ctor_parent(cx).is_lang_item(cx, LangItem::OptionNone)
|
||||
&& let Some((_, Node::Expr(_block))) = parent_iter.next()
|
||||
// This includes the function header
|
||||
&& let Some((_, func)) = parent_iter.next()
|
||||
|
|
|
|||
|
|
@ -2,9 +2,10 @@ use super::MANUAL_FLATTEN;
|
|||
use super::utils::make_iterator_snippet;
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::msrvs::{self, Msrv};
|
||||
use clippy_utils::res::MaybeResPath;
|
||||
use clippy_utils::source::{HasSession, indent_of, reindent_multiline, snippet_with_applicability};
|
||||
use clippy_utils::visitors::is_local_used;
|
||||
use clippy_utils::{higher, is_refutable, path_to_local_id, peel_blocks_with_stmt, span_contains_comment};
|
||||
use clippy_utils::{higher, is_refutable, peel_blocks_with_stmt, span_contains_comment};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::{Expr, Pat, PatKind};
|
||||
|
|
@ -27,7 +28,7 @@ pub(super) fn check<'tcx>(
|
|||
= higher::IfLet::hir(cx, inner_expr)
|
||||
// Ensure match_expr in `if let` statement is the same as the pat from the for-loop
|
||||
&& let PatKind::Binding(_, pat_hir_id, _, _) = pat.kind
|
||||
&& path_to_local_id(let_expr, pat_hir_id)
|
||||
&& let_expr.res_local_id() == Some(pat_hir_id)
|
||||
// Ensure the `if let` statement is for the `Some` variant of `Option` or the `Ok` variant of `Result`
|
||||
&& let PatKind::TupleStruct(ref qpath, [inner_pat], _) = let_pat.kind
|
||||
&& let Res::Def(DefKind::Ctor(..), ctor_id) = cx.qpath_res(qpath, let_pat.hir_id)
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
use super::{IncrementVisitor, InitializeVisitor, MANUAL_MEMCPY};
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::res::MaybeResPath;
|
||||
use clippy_utils::source::snippet;
|
||||
use clippy_utils::sugg::Sugg;
|
||||
use clippy_utils::ty::is_copy;
|
||||
use clippy_utils::usage::local_used_in;
|
||||
use clippy_utils::{get_enclosing_block, higher, path_to_local, sugg};
|
||||
use clippy_utils::{get_enclosing_block, higher, sugg};
|
||||
use rustc_ast::ast;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::intravisit::walk_block;
|
||||
|
|
@ -67,7 +68,7 @@ pub(super) fn check<'tcx>(
|
|||
&& !local_used_in(cx, canonical_id, base_left)
|
||||
&& !local_used_in(cx, canonical_id, base_right)
|
||||
// Source and destination must be different
|
||||
&& path_to_local(base_left) != path_to_local(base_right)
|
||||
&& base_left.res_local_id() != base_right.res_local_id()
|
||||
{
|
||||
Some((
|
||||
ty,
|
||||
|
|
@ -128,7 +129,7 @@ fn build_manual_memcpy_suggestion<'tcx>(
|
|||
let print_limit = |end: &Expr<'_>, end_str: &str, base: &Expr<'_>, sugg: MinifyingSugg<'static>| {
|
||||
if let ExprKind::MethodCall(method, recv, [], _) = end.kind
|
||||
&& method.ident.name == sym::len
|
||||
&& path_to_local(recv) == path_to_local(base)
|
||||
&& recv.res_local_id() == base.res_local_id()
|
||||
{
|
||||
if sugg.to_string() == end_str {
|
||||
sugg::EMPTY.into()
|
||||
|
|
@ -364,7 +365,7 @@ fn get_details_from_idx<'tcx>(
|
|||
starts: &[Start<'tcx>],
|
||||
) -> Option<(StartKind<'tcx>, Offset)> {
|
||||
fn get_start<'tcx>(e: &Expr<'_>, starts: &[Start<'tcx>]) -> Option<StartKind<'tcx>> {
|
||||
let id = path_to_local(e)?;
|
||||
let id = e.res_local_id()?;
|
||||
starts.iter().find(|start| start.id == id).map(|start| start.kind)
|
||||
}
|
||||
|
||||
|
|
@ -425,7 +426,7 @@ fn get_assignments<'a, 'tcx>(
|
|||
.chain(*expr)
|
||||
.filter(move |e| {
|
||||
if let ExprKind::AssignOp(_, place, _) = e.kind {
|
||||
path_to_local(place).is_some_and(|id| {
|
||||
place.res_local_id().is_some_and(|id| {
|
||||
!loop_counters
|
||||
.iter()
|
||||
// skip the first item which should be `StartKind::Range`
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use super::MISSING_SPIN_LOOP;
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::res::MaybeDef;
|
||||
use clippy_utils::std_or_core;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Block, Expr, ExprKind};
|
||||
use rustc_lint::LateContext;
|
||||
|
|
@ -40,7 +40,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, cond: &'tcx Expr<'_>, body: &'
|
|||
&& let ExprKind::MethodCall(method, callee, ..) = unpack_cond(cond).kind
|
||||
&& [sym::load, sym::compare_exchange, sym::compare_exchange_weak].contains(&method.ident.name)
|
||||
&& let callee_ty = cx.typeck_results().expr_ty(callee)
|
||||
&& is_type_diagnostic_item(cx, callee_ty, sym::AtomicBool)
|
||||
&& callee_ty.is_diag_item(cx, sym::AtomicBool)
|
||||
&& let Some(std_or_core) = std_or_core(cx)
|
||||
{
|
||||
span_lint_and_sugg(
|
||||
|
|
|
|||
|
|
@ -861,6 +861,7 @@ impl<'tcx> LateLintPass<'tcx> for Loops {
|
|||
// check for `loop { if let {} else break }` that could be `while let`
|
||||
// (also matches an explicit "match" instead of "if let")
|
||||
// (even if the "match" or "if let" is used for declaration)
|
||||
// (also matches on `let {} else break`)
|
||||
if let ExprKind::Loop(block, label, LoopSource::Loop, _) = expr.kind {
|
||||
// also check for empty `loop {}` statements, skipping those in #[panic_handler]
|
||||
empty_loop::check(cx, expr, block);
|
||||
|
|
@ -870,7 +871,10 @@ impl<'tcx> LateLintPass<'tcx> for Loops {
|
|||
|
||||
while_let_on_iterator::check(cx, expr);
|
||||
|
||||
if let Some(higher::While { condition, body, span }) = higher::While::hir(expr) {
|
||||
if let Some(higher::While {
|
||||
condition, body, span, ..
|
||||
}) = higher::While::hir(expr)
|
||||
{
|
||||
while_immutable_condition::check(cx, condition, body);
|
||||
while_float::check(cx, condition);
|
||||
missing_spin_loop::check(cx, condition, body);
|
||||
|
|
@ -880,7 +884,7 @@ impl<'tcx> LateLintPass<'tcx> for Loops {
|
|||
}
|
||||
|
||||
impl Loops {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
#[expect(clippy::too_many_arguments)]
|
||||
fn check_for_loop<'tcx>(
|
||||
&self,
|
||||
cx: &LateContext<'tcx>,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use super::MUT_RANGE_BOUND;
|
||||
use clippy_utils::diagnostics::span_lint_and_note;
|
||||
use clippy_utils::{get_enclosing_block, higher, path_to_local};
|
||||
use clippy_utils::res::MaybeResPath;
|
||||
use clippy_utils::{get_enclosing_block, higher};
|
||||
use rustc_hir::intravisit::{self, Visitor};
|
||||
use rustc_hir::{BindingMode, Expr, ExprKind, HirId, Node, PatKind};
|
||||
use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
|
||||
|
|
@ -39,7 +40,7 @@ fn mut_warn_with_span(cx: &LateContext<'_>, span: Option<Span>) {
|
|||
}
|
||||
|
||||
fn check_for_mutability(cx: &LateContext<'_>, bound: &Expr<'_>) -> Option<HirId> {
|
||||
if let Some(hir_id) = path_to_local(bound)
|
||||
if let Some(hir_id) = bound.res_local_id()
|
||||
&& let Node::Pat(pat) = cx.tcx.hir_node(hir_id)
|
||||
&& let PatKind::Binding(BindingMode::MUT, ..) = pat.kind
|
||||
{
|
||||
|
|
|
|||
|
|
@ -240,7 +240,7 @@ fn is_label_for_block(cx: &LateContext<'_>, dest: &Destination) -> bool {
|
|||
.is_ok_and(|hir_id| matches!(cx.tcx.hir_node(hir_id), Node::Block(_)))
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_lines)]
|
||||
#[expect(clippy::too_many_lines)]
|
||||
fn never_loop_expr<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
expr: &Expr<'tcx>,
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
use super::SAME_ITEM_PUSH;
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::msrvs::Msrv;
|
||||
use clippy_utils::res::{MaybeDef, MaybeResPath};
|
||||
use clippy_utils::source::snippet_with_context;
|
||||
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
|
||||
use clippy_utils::{msrvs, path_to_local, std_or_core, sym};
|
||||
use clippy_utils::ty::implements_trait;
|
||||
use clippy_utils::{msrvs, std_or_core, sym};
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
|
|
@ -125,7 +126,7 @@ impl<'a, 'tcx> SameItemPushVisitor<'a, 'tcx> {
|
|||
if !self.non_deterministic_expr
|
||||
&& !self.multiple_pushes
|
||||
&& let Some((vec, _, _)) = self.vec_push
|
||||
&& let Some(hir_id) = path_to_local(vec)
|
||||
&& let Some(hir_id) = vec.res_local_id()
|
||||
{
|
||||
!self.used_locals.contains(&hir_id)
|
||||
} else {
|
||||
|
|
@ -141,7 +142,7 @@ impl<'tcx> Visitor<'tcx> for SameItemPushVisitor<'_, 'tcx> {
|
|||
ExprKind::Loop(..) | ExprKind::Match(..) | ExprKind::If(..) => self.non_deterministic_expr = true,
|
||||
ExprKind::Block(block, _) => self.visit_block(block),
|
||||
_ => {
|
||||
if let Some(hir_id) = path_to_local(expr) {
|
||||
if let Some(hir_id) = expr.res_local_id() {
|
||||
self.used_locals.insert(hir_id);
|
||||
}
|
||||
walk_expr(self, expr);
|
||||
|
|
@ -186,7 +187,7 @@ fn get_vec_push<'tcx>(
|
|||
&& let ExprKind::MethodCall(path, self_expr, [pushed_item], _) = &semi_stmt.kind
|
||||
// Check that the method being called is push() on a Vec
|
||||
&& path.ident.name == sym::push
|
||||
&& is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_expr), sym::Vec)
|
||||
&& cx.typeck_results().expr_ty(self_expr).is_diag_item(cx, sym::Vec)
|
||||
{
|
||||
return Some((self_expr, pushed_item, semi_stmt.span.ctxt()));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use super::UNUSED_ENUMERATE_INDEX;
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::res::MaybeDef;
|
||||
use clippy_utils::source::snippet;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::{pat_is_wild, sugg};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::def::DefKind;
|
||||
|
|
@ -17,7 +17,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'tcx>, arg: &Expr<'_
|
|||
&& let ExprKind::MethodCall(_method, self_arg, [], _) = arg.kind
|
||||
&& let ty = cx.typeck_results().expr_ty(arg)
|
||||
&& pat_is_wild(cx, &index.kind, body)
|
||||
&& is_type_diagnostic_item(cx, ty, sym::Enumerate)
|
||||
&& ty.is_diag_item(cx, sym::Enumerate)
|
||||
&& let Some((DefKind::AssocFn, call_id)) = cx.typeck_results().type_dependent_def(arg.hir_id)
|
||||
&& cx.tcx.is_diagnostic_item(sym::enumerate_method, call_id)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use clippy_utils::res::MaybeResPath;
|
||||
use clippy_utils::ty::{has_iter_method, implements_trait};
|
||||
use clippy_utils::{get_parent_expr, is_integer_const, path_to_local, path_to_local_id, sugg};
|
||||
use clippy_utils::{get_parent_expr, is_integer_const, sugg};
|
||||
use rustc_ast::ast::{LitIntType, LitKind};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::intravisit::{Visitor, walk_expr, walk_local};
|
||||
|
|
@ -47,7 +48,7 @@ impl<'a, 'tcx> IncrementVisitor<'a, 'tcx> {
|
|||
impl<'tcx> Visitor<'tcx> for IncrementVisitor<'_, 'tcx> {
|
||||
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
|
||||
// If node is a variable
|
||||
if let Some(def_id) = path_to_local(expr) {
|
||||
if let Some(def_id) = expr.res_local_id() {
|
||||
if let Some(parent) = get_parent_expr(self.cx, expr) {
|
||||
let state = self.states.entry(def_id).or_insert(IncrementVisitorVarState::Initial);
|
||||
if *state == IncrementVisitorVarState::IncrOnce {
|
||||
|
|
@ -175,7 +176,7 @@ impl<'tcx> Visitor<'tcx> for InitializeVisitor<'_, 'tcx> {
|
|||
}
|
||||
|
||||
// If node is the desired variable, see how it's used
|
||||
if path_to_local_id(expr, self.var_id) {
|
||||
if expr.res_local_id() == Some(self.var_id) {
|
||||
if self.past_loop {
|
||||
self.state = InitializeVisitorState::DontWarn;
|
||||
return;
|
||||
|
|
@ -255,7 +256,7 @@ fn is_conditional(expr: &Expr<'_>) -> bool {
|
|||
|
||||
/// If `arg` was the argument to a `for` loop, return the "cleanest" way of writing the
|
||||
/// actual `Iterator` that the loop uses.
|
||||
pub(super) fn make_iterator_snippet(cx: &LateContext<'_>, arg: &Expr<'_>, applic_ref: &mut Applicability) -> String {
|
||||
pub(super) fn make_iterator_snippet(cx: &LateContext<'_>, arg: &Expr<'_>, applicability: &mut Applicability) -> String {
|
||||
let impls_iterator = cx
|
||||
.tcx
|
||||
.get_diagnostic_item(sym::Iterator)
|
||||
|
|
@ -263,7 +264,7 @@ pub(super) fn make_iterator_snippet(cx: &LateContext<'_>, arg: &Expr<'_>, applic
|
|||
if impls_iterator {
|
||||
format!(
|
||||
"{}",
|
||||
sugg::Sugg::hir_with_applicability(cx, arg, "_", applic_ref).maybe_paren()
|
||||
sugg::Sugg::hir_with_applicability(cx, arg, "_", applicability).maybe_paren()
|
||||
)
|
||||
} else {
|
||||
// (&x).into_iter() ==> x.iter()
|
||||
|
|
@ -281,12 +282,12 @@ pub(super) fn make_iterator_snippet(cx: &LateContext<'_>, arg: &Expr<'_>, applic
|
|||
};
|
||||
format!(
|
||||
"{}.{method_name}()",
|
||||
sugg::Sugg::hir_with_applicability(cx, caller, "_", applic_ref).maybe_paren(),
|
||||
sugg::Sugg::hir_with_applicability(cx, caller, "_", applicability).maybe_paren(),
|
||||
)
|
||||
},
|
||||
_ => format!(
|
||||
"{}.into_iter()",
|
||||
sugg::Sugg::hir_with_applicability(cx, arg, "_", applic_ref).maybe_paren()
|
||||
sugg::Sugg::hir_with_applicability(cx, arg, "_", applicability).maybe_paren()
|
||||
),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,19 +10,19 @@ use rustc_hir::{Block, Expr, ExprKind, LetStmt, MatchSource, Pat, PatKind, Path,
|
|||
use rustc_lint::LateContext;
|
||||
|
||||
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, loop_block: &'tcx Block<'_>) {
|
||||
let (init, let_info) = match (loop_block.stmts, loop_block.expr) {
|
||||
let (init, let_info, els) = match (loop_block.stmts, loop_block.expr) {
|
||||
([stmt, ..], _) => match stmt.kind {
|
||||
StmtKind::Let(LetStmt {
|
||||
init: Some(e),
|
||||
els: None,
|
||||
els,
|
||||
pat,
|
||||
ty,
|
||||
..
|
||||
}) => (*e, Some((*pat, *ty))),
|
||||
StmtKind::Semi(e) | StmtKind::Expr(e) => (e, None),
|
||||
}) => (*e, Some((*pat, *ty)), *els),
|
||||
StmtKind::Semi(e) | StmtKind::Expr(e) => (e, None, None),
|
||||
_ => return,
|
||||
},
|
||||
([], Some(e)) => (e, None),
|
||||
([], Some(e)) => (e, None, None),
|
||||
_ => return,
|
||||
};
|
||||
let has_trailing_exprs = loop_block.stmts.len() + usize::from(loop_block.expr.is_some()) > 1;
|
||||
|
|
@ -38,14 +38,26 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, loop_blo
|
|||
if_let.let_expr,
|
||||
has_trailing_exprs,
|
||||
let_info,
|
||||
if_let.if_then,
|
||||
Some(if_let.if_then),
|
||||
);
|
||||
} else if els.and_then(|x| x.expr).is_some_and(is_simple_break_expr)
|
||||
&& let Some((pat, _)) = let_info
|
||||
{
|
||||
could_be_while_let(cx, expr, pat, init, has_trailing_exprs, let_info, None);
|
||||
} else if let ExprKind::Match(scrutinee, [arm1, arm2], MatchSource::Normal) = init.kind
|
||||
&& arm1.guard.is_none()
|
||||
&& arm2.guard.is_none()
|
||||
&& is_simple_break_expr(arm2.body)
|
||||
{
|
||||
could_be_while_let(cx, expr, arm1.pat, scrutinee, has_trailing_exprs, let_info, arm1.body);
|
||||
could_be_while_let(
|
||||
cx,
|
||||
expr,
|
||||
arm1.pat,
|
||||
scrutinee,
|
||||
has_trailing_exprs,
|
||||
let_info,
|
||||
Some(arm1.body),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -70,7 +82,7 @@ fn could_be_while_let<'tcx>(
|
|||
let_expr: &'tcx Expr<'_>,
|
||||
has_trailing_exprs: bool,
|
||||
let_info: Option<(&Pat<'_>, Option<&Ty<'_>>)>,
|
||||
inner_expr: &Expr<'_>,
|
||||
inner_expr: Option<&Expr<'_>>,
|
||||
) {
|
||||
if has_trailing_exprs
|
||||
&& (needs_ordered_drop(cx, cx.typeck_results().expr_ty(let_expr))
|
||||
|
|
@ -85,7 +97,7 @@ fn could_be_while_let<'tcx>(
|
|||
// 1) it was ugly with big bodies;
|
||||
// 2) it was not indented properly;
|
||||
// 3) it wasn’t very smart (see #675).
|
||||
let inner_content = if let Some((pat, ty)) = let_info
|
||||
let inner_content = if let Some(((pat, ty), inner_expr)) = let_info.zip(inner_expr)
|
||||
// Prevent trivial reassignments such as `let x = x;` or `let _ = …;`, but
|
||||
// keep them if the type has been explicitly specified.
|
||||
&& (!is_trivial_assignment(pat, peel_blocks(inner_expr)) || ty.is_some())
|
||||
|
|
|
|||
|
|
@ -2,9 +2,10 @@ use std::ops::ControlFlow;
|
|||
|
||||
use super::WHILE_LET_ON_ITERATOR;
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::res::{MaybeDef, MaybeTypeckRes};
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::visitors::is_res_used;
|
||||
use clippy_utils::{get_enclosing_loop_or_multi_call_closure, higher, is_refutable, is_res_lang_ctor, is_trait_method};
|
||||
use clippy_utils::{get_enclosing_loop_or_multi_call_closure, higher, is_refutable};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_hir::intravisit::{Visitor, walk_expr};
|
||||
|
|
@ -19,11 +20,11 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
|||
if let Some(higher::WhileLet { if_then, let_pat, let_expr, label, .. }) = higher::WhileLet::hir(expr)
|
||||
// check for `Some(..)` pattern
|
||||
&& let PatKind::TupleStruct(ref pat_path, some_pat, _) = let_pat.kind
|
||||
&& is_res_lang_ctor(cx, cx.qpath_res(pat_path, let_pat.hir_id), LangItem::OptionSome)
|
||||
&& cx.qpath_res(pat_path, let_pat.hir_id).ctor_parent(cx).is_lang_item(cx, LangItem::OptionSome)
|
||||
// check for call to `Iterator::next`
|
||||
&& let ExprKind::MethodCall(method_name, iter_expr, [], _) = let_expr.kind
|
||||
&& method_name.ident.name == sym::next
|
||||
&& is_trait_method(cx, let_expr, sym::Iterator)
|
||||
&& cx.ty_based_def(let_expr).opt_parent(cx).is_diag_item(cx, sym::Iterator)
|
||||
&& let Some(iter_expr_struct) = try_parse_iter_expr(cx, iter_expr)
|
||||
// get the loop containing the match expression
|
||||
&& !uses_iter(cx, &iter_expr_struct, if_then)
|
||||
|
|
|
|||
|
|
@ -2,9 +2,10 @@ use clippy_config::Conf;
|
|||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::higher::If;
|
||||
use clippy_utils::msrvs::{self, Msrv};
|
||||
use clippy_utils::res::MaybeDef;
|
||||
use clippy_utils::source::HasSession as _;
|
||||
use clippy_utils::sugg::Sugg;
|
||||
use clippy_utils::ty::{is_type_diagnostic_item, peel_and_count_ty_refs};
|
||||
use clippy_utils::ty::peel_and_count_ty_refs;
|
||||
use clippy_utils::{eq_expr_value, peel_blocks, span_contains_comment};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{BinOpKind, Expr, ExprKind};
|
||||
|
|
@ -104,7 +105,7 @@ impl ManualAbsDiff {
|
|||
fn are_ty_eligible<'tcx>(&self, cx: &LateContext<'tcx>, a: &Expr<'_>, b: &Expr<'_>) -> Option<(Ty<'tcx>, usize)> {
|
||||
let is_int = |ty: Ty<'_>| matches!(ty.kind(), ty::Uint(_) | ty::Int(_)) && self.msrv.meets(cx, msrvs::ABS_DIFF);
|
||||
let is_duration =
|
||||
|ty| is_type_diagnostic_item(cx, ty, sym::Duration) && self.msrv.meets(cx, msrvs::DURATION_ABS_DIFF);
|
||||
|ty: Ty<'_>| ty.is_diag_item(cx, sym::Duration) && self.msrv.meets(cx, msrvs::DURATION_ABS_DIFF);
|
||||
|
||||
let a_ty = cx.typeck_results().expr_ty(a).peel_refs();
|
||||
let (b_ty, b_n_refs, _) = peel_and_count_ty_refs(cx.typeck_results().expr_ty(b));
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::macros::{is_panic, root_macro_call};
|
||||
use clippy_utils::source::{indent_of, reindent_multiline};
|
||||
use clippy_utils::{higher, is_else_clause, is_parent_stmt, peel_blocks_with_stmt, span_extract_comment, sugg};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, ExprKind};
|
||||
|
|
@ -50,32 +51,32 @@ impl<'tcx> LateLintPass<'tcx> for ManualAssert {
|
|||
// Should this have a config value?
|
||||
&& !is_else_clause(cx.tcx, expr)
|
||||
{
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let mut comments = span_extract_comment(cx.sess().source_map(), expr.span);
|
||||
if !comments.is_empty() {
|
||||
comments += "\n";
|
||||
}
|
||||
let cond_sugg = !sugg::Sugg::hir_with_context(cx, cond, expr.span.ctxt(), "..", &mut applicability);
|
||||
let semicolon = if is_parent_stmt(cx, expr.hir_id) { ";" } else { "" };
|
||||
let sugg = format!("assert!({cond_sugg}, {format_args_snip}){semicolon}");
|
||||
// we show to the user the suggestion without the comments, but when applying the fix, include the
|
||||
// comments in the block
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
MANUAL_ASSERT,
|
||||
expr.span,
|
||||
"only a `panic!` in `if`-then statement",
|
||||
|diag| {
|
||||
// comments can be noisy, do not show them to the user
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let mut comments = span_extract_comment(cx.sess().source_map(), expr.span);
|
||||
if !comments.is_empty() {
|
||||
diag.tool_only_span_suggestion(
|
||||
expr.span.shrink_to_lo(),
|
||||
"add comments back",
|
||||
comments,
|
||||
applicability,
|
||||
);
|
||||
comments += "\n";
|
||||
}
|
||||
diag.span_suggestion(expr.span, "try instead", sugg, applicability);
|
||||
let cond_sugg = !sugg::Sugg::hir_with_context(cx, cond, expr.span.ctxt(), "..", &mut applicability);
|
||||
let semicolon = if is_parent_stmt(cx, expr.hir_id) { ";" } else { "" };
|
||||
|
||||
let indent = indent_of(cx, expr.span);
|
||||
let full_sugg = reindent_multiline(
|
||||
format!("{comments}assert!({cond_sugg}, {format_args_snip}){semicolon}").as_str(),
|
||||
true,
|
||||
indent,
|
||||
);
|
||||
diag.span_suggestion_verbose(
|
||||
expr.span,
|
||||
"replace `if`-then-`panic!` with `assert!`",
|
||||
full_sugg,
|
||||
applicability,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,13 +3,11 @@ use clippy_utils::consts::{ConstEvalCtxt, Constant};
|
|||
use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then};
|
||||
use clippy_utils::higher::If;
|
||||
use clippy_utils::msrvs::{self, Msrv};
|
||||
use clippy_utils::res::{MaybeDef, MaybeResPath, MaybeTypeckRes};
|
||||
use clippy_utils::sugg::Sugg;
|
||||
use clippy_utils::ty::implements_trait;
|
||||
use clippy_utils::visitors::is_const_evaluatable;
|
||||
use clippy_utils::{
|
||||
MaybePath, eq_expr_value, is_diag_trait_item, is_in_const_context, is_trait_method, path_res, path_to_local_id,
|
||||
peel_blocks, peel_blocks_with_stmt, sym,
|
||||
};
|
||||
use clippy_utils::{eq_expr_value, is_in_const_context, peel_blocks, peel_blocks_with_stmt, sym};
|
||||
use itertools::Itertools;
|
||||
use rustc_errors::{Applicability, Diag};
|
||||
use rustc_hir::def::Res;
|
||||
|
|
@ -292,10 +290,12 @@ fn is_if_elseif_else_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx
|
|||
/// # ;
|
||||
/// ```
|
||||
fn is_max_min_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option<ClampSuggestion<'tcx>> {
|
||||
if let ExprKind::MethodCall(seg_second, receiver, [arg_second], _) = &expr.kind
|
||||
&& (cx.typeck_results().expr_ty_adjusted(receiver).is_floating_point() || is_trait_method(cx, expr, sym::Ord))
|
||||
if let ExprKind::MethodCall(seg_second, receiver, [arg_second], _) = expr.kind
|
||||
&& (cx.typeck_results().expr_ty_adjusted(receiver).is_floating_point()
|
||||
|| cx.ty_based_def(expr).assoc_fn_parent(cx).is_diag_item(cx, sym::Ord))
|
||||
&& let ExprKind::MethodCall(seg_first, input, [arg_first], _) = &receiver.kind
|
||||
&& (cx.typeck_results().expr_ty_adjusted(input).is_floating_point() || is_trait_method(cx, receiver, sym::Ord))
|
||||
&& (cx.typeck_results().expr_ty_adjusted(input).is_floating_point()
|
||||
|| cx.ty_based_def(receiver).assoc_fn_parent(cx).is_diag_item(cx, sym::Ord))
|
||||
{
|
||||
let is_float = cx.typeck_results().expr_ty_adjusted(input).is_floating_point();
|
||||
let (min, max) = match (seg_first.ident.name, seg_second.ident.name) {
|
||||
|
|
@ -331,18 +331,18 @@ fn is_call_max_min_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>)
|
|||
fn segment<'tcx>(cx: &LateContext<'_>, func: &Expr<'tcx>) -> Option<FunctionType<'tcx>> {
|
||||
match func.kind {
|
||||
ExprKind::Path(QPath::Resolved(None, path)) => {
|
||||
let id = path.res.opt_def_id()?;
|
||||
match cx.tcx.get_diagnostic_name(id) {
|
||||
let def = path.res.opt_def(cx)?;
|
||||
match cx.tcx.get_diagnostic_name(def.1) {
|
||||
Some(sym::cmp_min) => Some(FunctionType::CmpMin),
|
||||
Some(sym::cmp_max) => Some(FunctionType::CmpMax),
|
||||
_ if is_diag_trait_item(cx, id, sym::Ord) => {
|
||||
_ if def.assoc_fn_parent(cx).is_diag_item(cx, sym::Ord) => {
|
||||
Some(FunctionType::OrdOrFloat(path.segments.last().expect("infallible")))
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
},
|
||||
ExprKind::Path(QPath::TypeRelative(ty, seg)) => {
|
||||
matches!(path_res(cx, ty), Res::PrimTy(PrimTy::Float(_))).then(|| FunctionType::OrdOrFloat(seg))
|
||||
matches!(ty.basic_res(), Res::PrimTy(PrimTy::Float(_))).then(|| FunctionType::OrdOrFloat(seg))
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
|
|
@ -435,7 +435,7 @@ fn is_match_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Opt
|
|||
let first = BinaryOp::new(first)?;
|
||||
let second = BinaryOp::new(second)?;
|
||||
if let PatKind::Binding(_, binding, _, None) = &last_arm.pat.kind
|
||||
&& path_to_local_id(peel_blocks_with_stmt(last_arm.body), *binding)
|
||||
&& peel_blocks_with_stmt(last_arm.body).res_local_id() == Some(*binding)
|
||||
&& last_arm.guard.is_none()
|
||||
{
|
||||
// Proceed as normal
|
||||
|
|
@ -516,7 +516,7 @@ fn is_two_if_pattern<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) ->
|
|||
},
|
||||
span: first_expr.span.to(second_expr.span),
|
||||
make_assignment: Some(maybe_input_first_path),
|
||||
hir_with_ignore_attr: Some(first_expr.hir_id()),
|
||||
hir_with_ignore_attr: Some(first_expr.hir_id),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
|
|
@ -655,8 +655,8 @@ fn is_clamp_meta_pattern<'tcx>(
|
|||
let (min, max) = (second_expr, first_expr);
|
||||
let refers_to_input = match input_hir_ids {
|
||||
Some((first_hir_id, second_hir_id)) => {
|
||||
path_to_local_id(peel_blocks(first_bin.left), first_hir_id)
|
||||
&& path_to_local_id(peel_blocks(second_bin.left), second_hir_id)
|
||||
peel_blocks(first_bin.left).res_local_id() == Some(first_hir_id)
|
||||
&& peel_blocks(second_bin.left).res_local_id() == Some(second_hir_id)
|
||||
},
|
||||
None => eq_expr_value(cx, first_bin.left, second_bin.left),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::msrvs::{self, Msrv};
|
||||
use clippy_utils::source::snippet_with_context;
|
||||
use clippy_utils::sugg::{Sugg, has_enclosing_paren};
|
||||
use clippy_utils::{SpanlessEq, sym};
|
||||
use rustc_ast::{BinOpKind, LitIntType, LitKind, UnOp};
|
||||
|
|
@ -165,6 +164,7 @@ fn build_suggestion(
|
|||
applicability: &mut Applicability,
|
||||
) {
|
||||
let dividend_sugg = Sugg::hir_with_applicability(cx, lhs, "..", applicability).maybe_paren();
|
||||
let rhs_ty = cx.typeck_results().expr_ty(rhs);
|
||||
let type_suffix = if cx.typeck_results().expr_ty(lhs).is_numeric()
|
||||
&& matches!(
|
||||
lhs.kind,
|
||||
|
|
@ -182,7 +182,7 @@ fn build_suggestion(
|
|||
}
|
||||
)
|
||||
) {
|
||||
format!("_{}", cx.typeck_results().expr_ty(rhs))
|
||||
format!("_{rhs_ty}")
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
|
|
@ -199,9 +199,12 @@ fn build_suggestion(
|
|||
} else {
|
||||
format!("{dividend_sugg_str}{type_suffix}")
|
||||
};
|
||||
let divisor_snippet = snippet_with_context(cx, rhs.span, expr.span.ctxt(), "..", applicability);
|
||||
|
||||
let sugg = format!("{suggestion_before_div_ceil}.div_ceil({})", divisor_snippet.0);
|
||||
// Dereference the RHS if it is a reference type
|
||||
let divisor_snippet = match Sugg::hir_with_context(cx, rhs, expr.span.ctxt(), "_", applicability) {
|
||||
sugg if rhs_ty.is_ref() => sugg.deref(),
|
||||
sugg => sugg,
|
||||
};
|
||||
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
|
|
@ -209,7 +212,7 @@ fn build_suggestion(
|
|||
expr.span,
|
||||
"manually reimplementing `div_ceil`",
|
||||
"consider using `.div_ceil()`",
|
||||
sugg,
|
||||
format!("{suggestion_before_div_ceil}.div_ceil({divisor_snippet})"),
|
||||
*applicability,
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
use clippy_config::Conf;
|
||||
use clippy_utils::consts::ConstEvalCtxt;
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::is_from_proc_macro;
|
||||
use clippy_utils::msrvs::{self, Msrv};
|
||||
use clippy_utils::res::MaybeResPath;
|
||||
use clippy_utils::source::SpanRangeExt;
|
||||
use clippy_utils::{is_from_proc_macro, path_to_local};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::DefId;
|
||||
|
|
@ -138,7 +139,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualFloatMethods {
|
|||
// Checking all possible scenarios using a function would be a hopeless task, as we have
|
||||
// 16 possible alignments of constants/operands. For now, let's use `partition`.
|
||||
&& let mut exprs = [lhs_lhs, lhs_rhs, rhs_lhs, rhs_rhs]
|
||||
&& exprs.iter_mut().partition_in_place(|i| path_to_local(i).is_some()) == 2
|
||||
&& exprs.iter_mut().partition_in_place(|i| i.res_local_id().is_some()) == 2
|
||||
&& !expr.span.in_external_macro(cx.sess().source_map())
|
||||
&& (
|
||||
is_not_const(cx.tcx, cx.tcx.hir_enclosing_body_owner(expr.hir_id).into())
|
||||
|
|
@ -149,7 +150,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualFloatMethods {
|
|||
&& let ctxt = expr.span.ctxt()
|
||||
&& let Some(const_1) = ecx.eval_local(const_1, ctxt)
|
||||
&& let Some(const_2) = ecx.eval_local(const_2, ctxt)
|
||||
&& path_to_local(first).is_some_and(|f| path_to_local(second).is_some_and(|s| f == s))
|
||||
&& first.res_local_id().is_some_and(|f| second.res_local_id().is_some_and(|s| f == s))
|
||||
// The actual infinity check, we also allow `NEG_INFINITY` before` INFINITY` just in
|
||||
// case somebody does that for some reason
|
||||
&& (const_1.is_pos_infinity() && const_2.is_neg_infinity()
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::span_lint_hir_and_then;
|
||||
use clippy_utils::msrvs::{self, Msrv};
|
||||
use clippy_utils::res::{MaybeDef, MaybeResPath, MaybeTypeckRes};
|
||||
use clippy_utils::source::SpanRangeExt;
|
||||
use clippy_utils::sym;
|
||||
use clippy_utils::visitors::{is_local_used, local_used_once};
|
||||
use clippy_utils::{is_trait_method, path_to_local_id, sym};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{BindingMode, ExprKind, LetStmt, Node, PatKind, StmtKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
|
|
@ -81,8 +82,8 @@ impl LateLintPass<'_> for ManualHashOne {
|
|||
&& !hash_expr.span.from_expansion()
|
||||
&& let ExprKind::MethodCall(seg, hashed_value, [ref_to_hasher], _) = hash_expr.kind
|
||||
&& seg.ident.name == sym::hash
|
||||
&& is_trait_method(cx, hash_expr, sym::Hash)
|
||||
&& path_to_local_id(ref_to_hasher.peel_borrows(), hasher)
|
||||
&& cx.ty_based_def(hash_expr).opt_parent(cx).is_diag_item(cx, sym::Hash)
|
||||
&& ref_to_hasher.peel_borrows().res_local_id() == Some(hasher)
|
||||
|
||||
&& let maybe_finish_stmt = stmts.next()
|
||||
// There should be no more statements referencing `hasher`
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
use crate::manual_ignore_case_cmp::MatchType::{Literal, ToAscii};
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::res::MaybeDef;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::sym;
|
||||
use clippy_utils::ty::{get_type_diagnostic_name, is_type_diagnostic_item, is_type_lang_item};
|
||||
use rustc_ast::LitKind;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::ExprKind::{Binary, Lit, MethodCall};
|
||||
|
|
@ -58,7 +58,7 @@ fn get_ascii_type<'a>(cx: &LateContext<'a>, kind: rustc_hir::ExprKind<'_>) -> Op
|
|||
if needs_ref_to_cmp(cx, ty)
|
||||
|| ty.is_str()
|
||||
|| ty.is_slice()
|
||||
|| matches!(get_type_diagnostic_name(cx, ty), Some(sym::OsStr | sym::OsString))
|
||||
|| matches!(ty.opt_diag_name(cx), Some(sym::OsStr | sym::OsString))
|
||||
{
|
||||
return Some((expr.span, ToAscii(is_lower, ty_raw)));
|
||||
}
|
||||
|
|
@ -72,8 +72,8 @@ fn get_ascii_type<'a>(cx: &LateContext<'a>, kind: rustc_hir::ExprKind<'_>) -> Op
|
|||
fn needs_ref_to_cmp(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
|
||||
ty.is_char()
|
||||
|| *ty.kind() == ty::Uint(UintTy::U8)
|
||||
|| is_type_diagnostic_item(cx, ty, sym::Vec)
|
||||
|| is_type_lang_item(cx, ty, LangItem::String)
|
||||
|| ty.is_diag_item(cx, sym::Vec)
|
||||
|| ty.is_lang_item(cx, LangItem::String)
|
||||
}
|
||||
|
||||
impl LateLintPass<'_> for ManualIgnoreCaseCmp {
|
||||
|
|
|
|||
|
|
@ -2,8 +2,9 @@ use clippy_config::Conf;
|
|||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::macros::matching_root_macro_call;
|
||||
use clippy_utils::msrvs::{self, Msrv};
|
||||
use clippy_utils::res::MaybeResPath;
|
||||
use clippy_utils::sugg::Sugg;
|
||||
use clippy_utils::{higher, is_in_const_context, path_to_local, peel_ref_operators, sym};
|
||||
use clippy_utils::{higher, is_in_const_context, peel_ref_operators, sym};
|
||||
use rustc_ast::LitKind::{Byte, Char};
|
||||
use rustc_ast::ast::RangeLimits;
|
||||
use rustc_errors::Applicability;
|
||||
|
|
@ -125,7 +126,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck {
|
|||
}
|
||||
|
||||
fn get_ty_sugg<'tcx>(cx: &LateContext<'tcx>, arg: &Expr<'_>) -> Option<(Span, Ty<'tcx>)> {
|
||||
let local_hid = path_to_local(arg)?;
|
||||
let local_hid = arg.res_local_id()?;
|
||||
if let Node::Param(Param { ty_span, span, .. }) = cx.tcx.parent_hir_node(local_hid)
|
||||
// `ty_span` and `span` are the same for inferred type, thus a type suggestion must be given
|
||||
&& ty_span == span
|
||||
|
|
|
|||
|
|
@ -2,16 +2,14 @@ use crate::question_mark::{QUESTION_MARK, QuestionMark};
|
|||
use clippy_config::types::MatchLintBehaviour;
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::higher::IfLetOrMatch;
|
||||
use clippy_utils::res::{MaybeDef, MaybeQPath};
|
||||
use clippy_utils::source::snippet_with_context;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::{
|
||||
MaybePath, is_lint_allowed, is_never_expr, is_wild, msrvs, pat_and_expr_can_be_question_mark, path_res, peel_blocks,
|
||||
};
|
||||
use clippy_utils::{is_lint_allowed, is_never_expr, is_wild, msrvs, pat_and_expr_can_be_question_mark, peel_blocks};
|
||||
use rustc_ast::BindingMode;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::def::{CtorOf, DefKind, Res};
|
||||
use rustc_hir::{Arm, Expr, ExprKind, HirId, MatchSource, Pat, PatExpr, PatExprKind, PatKind, QPath, Stmt, StmtKind};
|
||||
use rustc_hir::{Arm, Expr, ExprKind, MatchSource, Pat, PatExpr, PatExprKind, PatKind, QPath, Stmt, StmtKind};
|
||||
use rustc_lint::{LateContext, LintContext};
|
||||
use rustc_span::Span;
|
||||
use rustc_span::symbol::{Symbol, sym};
|
||||
|
|
@ -131,39 +129,25 @@ fn is_arms_disjointed(cx: &LateContext<'_>, arm1: &Arm<'_>, arm2: &Arm<'_>) -> b
|
|||
|
||||
/// Returns `true` if the given pattern is a variant of an enum.
|
||||
pub fn is_enum_variant(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool {
|
||||
struct Pat<'hir>(&'hir rustc_hir::Pat<'hir>);
|
||||
|
||||
impl<'hir> MaybePath<'hir> for Pat<'hir> {
|
||||
fn qpath_opt(&self) -> Option<&QPath<'hir>> {
|
||||
match self.0.kind {
|
||||
PatKind::Struct(ref qpath, fields, _)
|
||||
if fields
|
||||
.iter()
|
||||
.all(|field| is_wild(field.pat) || matches!(field.pat.kind, PatKind::Binding(..))) =>
|
||||
{
|
||||
Some(qpath)
|
||||
},
|
||||
PatKind::TupleStruct(ref qpath, pats, _)
|
||||
if pats
|
||||
.iter()
|
||||
.all(|pat| is_wild(pat) || matches!(pat.kind, PatKind::Binding(..))) =>
|
||||
{
|
||||
Some(qpath)
|
||||
},
|
||||
PatKind::Expr(&PatExpr {
|
||||
kind: PatExprKind::Path(ref qpath),
|
||||
..
|
||||
}) => Some(qpath),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn hir_id(&self) -> HirId {
|
||||
self.0.hir_id
|
||||
}
|
||||
}
|
||||
|
||||
let res = path_res(cx, &Pat(pat));
|
||||
let path = match pat.kind {
|
||||
PatKind::Struct(ref qpath, fields, _)
|
||||
if fields
|
||||
.iter()
|
||||
.all(|field| is_wild(field.pat) || matches!(field.pat.kind, PatKind::Binding(..))) =>
|
||||
{
|
||||
(qpath, pat.hir_id)
|
||||
},
|
||||
PatKind::TupleStruct(ref qpath, pats, _)
|
||||
if pats
|
||||
.iter()
|
||||
.all(|pat| is_wild(pat) || matches!(pat.kind, PatKind::Binding(..))) =>
|
||||
{
|
||||
(qpath, pat.hir_id)
|
||||
},
|
||||
PatKind::Expr(e) if let Some((qpath, id)) = e.opt_qpath() => (qpath, id),
|
||||
_ => return false,
|
||||
};
|
||||
let res = path.res(cx);
|
||||
matches!(
|
||||
res,
|
||||
Res::Def(DefKind::Variant, ..) | Res::Def(DefKind::Ctor(CtorOf::Variant, _), _)
|
||||
|
|
@ -384,7 +368,7 @@ fn pat_allowed_for_else(cx: &LateContext<'_>, pat: &'_ Pat<'_>, check_types: boo
|
|||
}
|
||||
let ty = typeck_results.pat_ty(pat);
|
||||
// Option and Result are allowed, everything else isn't.
|
||||
if !(is_type_diagnostic_item(cx, ty, sym::Option) || is_type_diagnostic_item(cx, ty, sym::Result)) {
|
||||
if !(ty.is_diag_item(cx, sym::Option) || ty.is_diag_item(cx, sym::Result)) {
|
||||
has_disallowed = true;
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::msrvs::{self, Msrv};
|
||||
use clippy_utils::{is_trait_method, peel_hir_expr_refs};
|
||||
use clippy_utils::peel_hir_expr_refs;
|
||||
use clippy_utils::res::{MaybeDef, MaybeTypeckRes};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::{Expr, ExprKind, Mutability, QPath};
|
||||
|
|
@ -52,7 +53,7 @@ impl LateLintPass<'_> for ManualMainSeparatorStr {
|
|||
&& path.ident.name == sym::to_string
|
||||
&& let ExprKind::Path(QPath::Resolved(None, path)) = receiver.kind
|
||||
&& let Res::Def(DefKind::Const, receiver_def_id) = path.res
|
||||
&& is_trait_method(cx, target, sym::ToString)
|
||||
&& cx.ty_based_def(target).opt_parent(cx).is_diag_item(cx, sym::ToString)
|
||||
&& cx.tcx.is_diagnostic_item(sym::path_main_separator, receiver_def_id)
|
||||
&& let ty::Ref(_, ty, Mutability::Not) = cx.typeck_results().expr_ty_adjusted(expr).kind()
|
||||
&& ty.is_str()
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use clippy_config::Conf;
|
||||
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
|
||||
use clippy_utils::msrvs::Msrv;
|
||||
use clippy_utils::res::{MaybeDef, MaybeQPath, MaybeResPath};
|
||||
use clippy_utils::{is_none_pattern, msrvs, peel_hir_expr_refs, sym};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
|
|
@ -189,7 +190,7 @@ fn check_arms(cx: &LateContext<'_>, none_arm: &Arm<'_>, some_arm: &Arm<'_>) -> b
|
|||
|
||||
fn returns_empty_slice(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
|
||||
match expr.kind {
|
||||
ExprKind::Path(_) => clippy_utils::is_path_diagnostic_item(cx, expr, sym::default_fn),
|
||||
ExprKind::Path(_) => expr.res(cx).is_diag_item(cx, sym::default_fn),
|
||||
ExprKind::Closure(cl) => is_empty_slice(cx, cx.tcx.hir_body(cl.body).value),
|
||||
_ => false,
|
||||
}
|
||||
|
|
@ -214,11 +215,11 @@ fn is_empty_slice(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
|
|||
_ => false,
|
||||
},
|
||||
ExprKind::Array([]) => true,
|
||||
ExprKind::Call(def, []) => clippy_utils::is_path_diagnostic_item(cx, def, sym::default_fn),
|
||||
ExprKind::Call(def, []) => def.res(cx).is_diag_item(cx, sym::default_fn),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_slice_from_ref(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
|
||||
clippy_utils::is_path_diagnostic_item(cx, expr, sym::slice_from_ref)
|
||||
expr.basic_res().is_diag_item(cx, sym::slice_from_ref)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
use clippy_config::Conf;
|
||||
use clippy_utils::consts::{ConstEvalCtxt, FullInt};
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::is_in_const_context;
|
||||
use clippy_utils::msrvs::{self, Msrv};
|
||||
use clippy_utils::res::MaybeResPath;
|
||||
use clippy_utils::source::snippet_with_context;
|
||||
use clippy_utils::{is_in_const_context, path_to_local};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{BinOpKind, Expr, ExprKind, Node, TyKind};
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
|
|
@ -64,7 +65,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualRemEuclid {
|
|||
&& let ExprKind::Binary(rem2_op, rem2_lhs, rem2_rhs) = add_other.kind
|
||||
&& rem2_op.node == BinOpKind::Rem
|
||||
&& const1 == const2
|
||||
&& let Some(hir_id) = path_to_local(rem2_lhs)
|
||||
&& let Some(hir_id) = rem2_lhs.res_local_id()
|
||||
&& let Some(const3) = check_for_unsigned_int_constant(cx, ctxt, rem2_rhs)
|
||||
// Also ensures the const is nonzero since zero can't be a divisor
|
||||
&& const2 == const3
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ use clippy_config::Conf;
|
|||
use clippy_utils::SpanlessEq;
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::msrvs::{self, Msrv};
|
||||
use clippy_utils::res::MaybeDef;
|
||||
use clippy_utils::source::snippet;
|
||||
use clippy_utils::ty::{get_type_diagnostic_name, is_type_lang_item};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::ExprKind::Assign;
|
||||
|
|
@ -189,7 +189,7 @@ fn check_to_owned(
|
|||
&& let Some(chars_expr_def_id) = cx.typeck_results().type_dependent_def_id(chars_expr.hir_id)
|
||||
&& cx.tcx.is_diagnostic_item(sym::str_chars, chars_expr_def_id)
|
||||
&& let ty = cx.typeck_results().expr_ty(str_expr).peel_refs()
|
||||
&& is_type_lang_item(cx, ty, hir::LangItem::String)
|
||||
&& ty.is_lang_item(cx, hir::LangItem::String)
|
||||
&& SpanlessEq::new(cx).eq_expr(left_expr, str_expr)
|
||||
&& let hir::ExprKind::MethodCall(_, _, [closure_expr], _) = filter_expr.kind
|
||||
&& let hir::ExprKind::Closure(closure) = closure_expr.kind
|
||||
|
|
@ -250,7 +250,7 @@ fn match_acceptable_sym(cx: &LateContext<'_>, collect_def_id: DefId) -> bool {
|
|||
|
||||
fn match_acceptable_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>, msrv: Msrv) -> bool {
|
||||
let ty = cx.typeck_results().expr_ty(expr).peel_refs();
|
||||
let required = match get_type_diagnostic_name(cx, ty) {
|
||||
let required = match ty.opt_diag_name(cx) {
|
||||
Some(sym::BinaryHeap) => msrvs::BINARY_HEAP_RETAIN,
|
||||
Some(sym::BTreeSet) => msrvs::BTREE_SET_RETAIN,
|
||||
Some(sym::BTreeMap) => msrvs::BTREE_MAP_RETAIN,
|
||||
|
|
@ -264,7 +264,7 @@ fn match_acceptable_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>, msrv: Msrv)
|
|||
|
||||
fn match_map_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
|
||||
let ty = cx.typeck_results().expr_ty(expr).peel_refs();
|
||||
matches!(get_type_diagnostic_name(cx, ty), Some(sym::BTreeMap | sym::HashMap))
|
||||
matches!(ty.opt_diag_name(cx), Some(sym::BTreeMap | sym::HashMap))
|
||||
}
|
||||
|
||||
fn make_span_lint_and_sugg(cx: &LateContext<'_>, span: Span, sugg: String) {
|
||||
|
|
|
|||
|
|
@ -56,20 +56,14 @@ impl Display for ShiftDirection {
|
|||
}
|
||||
}
|
||||
|
||||
fn parse_shift<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
expr: &'tcx Expr<'tcx>,
|
||||
) -> Option<(ShiftDirection, u128, &'tcx Expr<'tcx>)> {
|
||||
fn parse_shift<'tcx>(expr: &'tcx Expr<'tcx>) -> Option<(ShiftDirection, &'tcx Expr<'tcx>, &'tcx Expr<'tcx>)> {
|
||||
if let ExprKind::Binary(op, l, r) = expr.kind {
|
||||
let dir = match op.node {
|
||||
BinOpKind::Shl => ShiftDirection::Left,
|
||||
BinOpKind::Shr => ShiftDirection::Right,
|
||||
_ => return None,
|
||||
};
|
||||
let const_expr = ConstEvalCtxt::new(cx).eval_local(r, expr.span.ctxt())?;
|
||||
if let Constant::Int(shift) = const_expr {
|
||||
return Some((dir, shift, l));
|
||||
}
|
||||
return Some((dir, l, r));
|
||||
}
|
||||
None
|
||||
}
|
||||
|
|
@ -78,40 +72,62 @@ impl LateLintPass<'_> for ManualRotate {
|
|||
fn check_expr<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
|
||||
if let ExprKind::Binary(op, l, r) = expr.kind
|
||||
&& let BinOpKind::Add | BinOpKind::BitOr = op.node
|
||||
&& let Some((l_shift_dir, l_amount, l_expr)) = parse_shift(cx, l)
|
||||
&& let Some((r_shift_dir, r_amount, r_expr)) = parse_shift(cx, r)
|
||||
{
|
||||
if l_shift_dir == r_shift_dir {
|
||||
return;
|
||||
}
|
||||
if !clippy_utils::eq_expr_value(cx, l_expr, r_expr) {
|
||||
return;
|
||||
}
|
||||
let Some(bit_width) = (match cx.typeck_results().expr_ty(expr).kind() {
|
||||
&& let Some((l_shift_dir, l_expr, l_amount)) = parse_shift(l)
|
||||
&& let Some((r_shift_dir, r_expr, r_amount)) = parse_shift(r)
|
||||
&& l_shift_dir != r_shift_dir
|
||||
&& clippy_utils::eq_expr_value(cx, l_expr, r_expr)
|
||||
&& let Some(bit_width) = match cx.typeck_results().expr_ty(expr).kind() {
|
||||
ty::Int(itype) => itype.bit_width(),
|
||||
ty::Uint(itype) => itype.bit_width(),
|
||||
_ => return,
|
||||
}) else {
|
||||
return;
|
||||
};
|
||||
if l_amount + r_amount == u128::from(bit_width) {
|
||||
let (shift_function, amount) = if l_amount < r_amount {
|
||||
}
|
||||
{
|
||||
let const_eval = ConstEvalCtxt::new(cx);
|
||||
|
||||
let ctxt = expr.span.ctxt();
|
||||
let (shift_function, amount) = if let Some(Constant::Int(l_amount_val)) =
|
||||
const_eval.eval_local(l_amount, ctxt)
|
||||
&& let Some(Constant::Int(r_amount_val)) = const_eval.eval_local(r_amount, ctxt)
|
||||
&& l_amount_val + r_amount_val == u128::from(bit_width)
|
||||
{
|
||||
if l_amount_val < r_amount_val {
|
||||
(l_shift_dir, l_amount)
|
||||
} else {
|
||||
(r_shift_dir, r_amount)
|
||||
}
|
||||
} else {
|
||||
let (amount1, binop, minuend, amount2, shift_direction) = match (l_amount.kind, r_amount.kind) {
|
||||
(_, ExprKind::Binary(binop, minuend, other)) => (l_amount, binop, minuend, other, l_shift_dir),
|
||||
(ExprKind::Binary(binop, minuend, other), _) => (r_amount, binop, minuend, other, r_shift_dir),
|
||||
_ => return,
|
||||
};
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let expr_sugg = sugg::Sugg::hir_with_applicability(cx, l_expr, "_", &mut applicability).maybe_paren();
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
MANUAL_ROTATE,
|
||||
expr.span,
|
||||
"there is no need to manually implement bit rotation",
|
||||
"this expression can be rewritten as",
|
||||
format!("{expr_sugg}.{shift_function}({amount})"),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(Constant::Int(minuend)) = const_eval.eval_local(minuend, ctxt)
|
||||
&& clippy_utils::eq_expr_value(cx, amount1, amount2)
|
||||
// (x << s) | (x >> bit_width - s)
|
||||
&& ((binop.node == BinOpKind::Sub && u128::from(bit_width) == minuend)
|
||||
// (x << s) | (x >> (bit_width - 1) ^ s)
|
||||
|| (binop.node == BinOpKind::BitXor && u128::from(bit_width).checked_sub(minuend) == Some(1)))
|
||||
{
|
||||
// NOTE: we take these from the side that _doesn't_ have the binop, since it's probably simpler
|
||||
(shift_direction, amount1)
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let expr_sugg = sugg::Sugg::hir_with_applicability(cx, l_expr, "_", &mut applicability).maybe_paren();
|
||||
let amount = sugg::Sugg::hir_with_applicability(cx, amount, "_", &mut applicability);
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
MANUAL_ROTATE,
|
||||
expr.span,
|
||||
"there is no need to manually implement bit rotation",
|
||||
"this expression can be rewritten as",
|
||||
format!("{expr_sugg}.{shift_function}({amount})"),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::res::MaybeDef;
|
||||
use clippy_utils::source::{snippet, snippet_with_applicability, snippet_with_context};
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::{iter_input_pats, method_chain_args};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
|
|
@ -205,9 +205,9 @@ fn lint_map_unit_fn(
|
|||
) {
|
||||
let var_arg = &map_args.0;
|
||||
|
||||
let (map_type, variant, lint) = if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(var_arg), sym::Option) {
|
||||
let (map_type, variant, lint) = if cx.typeck_results().expr_ty(var_arg).is_diag_item(cx, sym::Option) {
|
||||
("Option", "Some", OPTION_MAP_UNIT_FN)
|
||||
} else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(var_arg), sym::Result) {
|
||||
} else if cx.typeck_results().expr_ty(var_arg).is_diag_item(cx, sym::Result) {
|
||||
("Result", "Ok", RESULT_MAP_UNIT_FN)
|
||||
} else {
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::res::MaybeDef;
|
||||
use clippy_utils::source::snippet_with_context;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::{higher, is_res_lang_ctor, sym};
|
||||
use clippy_utils::{higher, sym};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, ExprKind, LangItem, PatKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
|
|
@ -57,8 +57,8 @@ impl<'tcx> LateLintPass<'tcx> for MatchResultOk {
|
|||
if let ExprKind::MethodCall(ok_path, recv, [], ..) = let_expr.kind //check is expr.ok() has type Result<T,E>.ok(, _)
|
||||
&& let PatKind::TupleStruct(ref pat_path, [ok_pat], _) = let_pat.kind //get operation
|
||||
&& ok_path.ident.name == sym::ok
|
||||
&& is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result)
|
||||
&& is_res_lang_ctor(cx, cx.qpath_res(pat_path, let_pat.hir_id), LangItem::OptionSome)
|
||||
&& cx.typeck_results().expr_ty(recv).is_diag_item(cx, sym::Result)
|
||||
&& cx.qpath_res(pat_path, let_pat.hir_id).ctor_parent(cx).is_lang_item(cx, LangItem::OptionSome)
|
||||
&& let ctxt = expr.span.ctxt()
|
||||
&& let_expr.span.ctxt() == ctxt
|
||||
&& let_pat.span.ctxt() == ctxt
|
||||
|
|
|
|||
|
|
@ -1,18 +1,17 @@
|
|||
use clippy_utils::diagnostics::span_lint_hir_and_then;
|
||||
use clippy_utils::higher::IfLetOrMatch;
|
||||
use clippy_utils::msrvs::Msrv;
|
||||
use clippy_utils::res::{MaybeDef, MaybeResPath};
|
||||
use clippy_utils::source::snippet;
|
||||
use clippy_utils::visitors::is_local_used;
|
||||
use clippy_utils::{
|
||||
SpanlessEq, get_ref_operators, is_res_lang_ctor, is_unit_expr, path_to_local, peel_blocks_with_stmt,
|
||||
peel_ref_operators,
|
||||
};
|
||||
use clippy_utils::{SpanlessEq, get_ref_operators, is_unit_expr, peel_blocks_with_stmt, peel_ref_operators};
|
||||
use rustc_ast::BorrowKind;
|
||||
use rustc_errors::MultiSpan;
|
||||
use rustc_hir::LangItem::OptionNone;
|
||||
use rustc_hir::{Arm, Expr, ExprKind, HirId, Pat, PatExpr, PatExprKind, PatKind};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_span::Span;
|
||||
use rustc_span::symbol::Ident;
|
||||
|
||||
use super::{COLLAPSIBLE_MATCH, pat_contains_disallowed_or};
|
||||
|
||||
|
|
@ -35,7 +34,7 @@ pub(super) fn check_if_let<'tcx>(
|
|||
check_arm(cx, false, pat, let_expr, body, None, else_expr, msrv);
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
#[expect(clippy::too_many_arguments)]
|
||||
fn check_arm<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
outer_is_match: bool,
|
||||
|
|
@ -50,26 +49,28 @@ fn check_arm<'tcx>(
|
|||
if let Some(inner) = IfLetOrMatch::parse(cx, inner_expr)
|
||||
&& let Some((inner_scrutinee, inner_then_pat, inner_else_body)) = match inner {
|
||||
IfLetOrMatch::IfLet(scrutinee, pat, _, els, _) => Some((scrutinee, pat, els)),
|
||||
IfLetOrMatch::Match(scrutinee, arms, ..) => if arms.len() == 2 && arms.iter().all(|a| a.guard.is_none())
|
||||
// if there are more than two arms, collapsing would be non-trivial
|
||||
// one of the arms must be "wild-like"
|
||||
&& let Some(wild_idx) = arms.iter().rposition(|a| arm_is_wild_like(cx, a))
|
||||
{
|
||||
let (then, els) = (&arms[1 - wild_idx], &arms[wild_idx]);
|
||||
Some((scrutinee, then.pat, Some(els.body)))
|
||||
} else {
|
||||
None
|
||||
IfLetOrMatch::Match(scrutinee, arms, ..) => {
|
||||
if arms.len() == 2 && arms.iter().all(|a| a.guard.is_none())
|
||||
// if there are more than two arms, collapsing would be non-trivial
|
||||
// one of the arms must be "wild-like"
|
||||
&& let Some(wild_idx) = arms.iter().rposition(|a| arm_is_wild_like(cx, a))
|
||||
{
|
||||
let (then, els) = (&arms[1 - wild_idx], &arms[wild_idx]);
|
||||
Some((scrutinee, then.pat, Some(els.body)))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
}
|
||||
&& outer_pat.span.eq_ctxt(inner_scrutinee.span)
|
||||
// match expression must be a local binding
|
||||
// match <local> { .. }
|
||||
&& let Some(binding_id) = path_to_local(peel_ref_operators(cx, inner_scrutinee))
|
||||
&& let Some(binding_id) = peel_ref_operators(cx, inner_scrutinee).res_local_id()
|
||||
&& !pat_contains_disallowed_or(cx, inner_then_pat, msrv)
|
||||
// the binding must come from the pattern of the containing match arm
|
||||
// ..<local>.. => match <local> { .. }
|
||||
&& let (Some(binding_span), is_innermost_parent_pat_struct)
|
||||
= find_pat_binding_and_is_innermost_parent_pat_struct(outer_pat, binding_id)
|
||||
&& let (Some((binding_ident, binding_span)), is_innermost_parent_pat_struct) =
|
||||
find_pat_binding_and_is_innermost_parent_pat_struct(outer_pat, binding_id)
|
||||
// the "else" branches must be equal
|
||||
&& match (outer_else_body, inner_else_body) {
|
||||
(None, None) => true,
|
||||
|
|
@ -77,9 +78,7 @@ fn check_arm<'tcx>(
|
|||
(Some(a), Some(b)) => SpanlessEq::new(cx).eq_expr(a, b),
|
||||
}
|
||||
// the binding must not be used in the if guard
|
||||
&& outer_guard.is_none_or(
|
||||
|e| !is_local_used(cx, e, binding_id)
|
||||
)
|
||||
&& outer_guard.is_none_or(|e| !is_local_used(cx, e, binding_id))
|
||||
// ...or anywhere in the inner expression
|
||||
&& match inner {
|
||||
IfLetOrMatch::IfLet(_, _, body, els, _) => {
|
||||
|
|
@ -103,7 +102,7 @@ fn check_arm<'tcx>(
|
|||
// collapsing patterns need an explicit field name in struct pattern matching
|
||||
// ex: Struct {x: Some(1)}
|
||||
let replace_msg = if is_innermost_parent_pat_struct {
|
||||
format!(", prefixed by `{}`:", snippet(cx, binding_span, "their field name"))
|
||||
format!(", prefixed by `{binding_ident}: `")
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
|
|
@ -135,21 +134,24 @@ fn arm_is_wild_like(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
|
|||
kind: PatExprKind::Path(qpath),
|
||||
hir_id,
|
||||
..
|
||||
}) => is_res_lang_ctor(cx, cx.qpath_res(qpath, *hir_id), OptionNone),
|
||||
}) => cx
|
||||
.qpath_res(qpath, *hir_id)
|
||||
.ctor_parent(cx)
|
||||
.is_lang_item(cx, OptionNone),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn find_pat_binding_and_is_innermost_parent_pat_struct(pat: &Pat<'_>, hir_id: HirId) -> (Option<Span>, bool) {
|
||||
let mut span = None;
|
||||
fn find_pat_binding_and_is_innermost_parent_pat_struct(pat: &Pat<'_>, hir_id: HirId) -> (Option<(Ident, Span)>, bool) {
|
||||
let mut binding = None;
|
||||
let mut is_innermost_parent_pat_struct = false;
|
||||
pat.walk_short(|p| match &p.kind {
|
||||
pat.walk_short(|p| match p.kind {
|
||||
// ignore OR patterns
|
||||
PatKind::Or(_) => false,
|
||||
PatKind::Binding(_bm, _, _ident, _) => {
|
||||
PatKind::Binding(_bm, _, ident, _) => {
|
||||
let found = p.hir_id == hir_id;
|
||||
if found {
|
||||
span = Some(p.span);
|
||||
binding = Some((ident, p.span));
|
||||
}
|
||||
!found
|
||||
},
|
||||
|
|
@ -158,7 +160,7 @@ fn find_pat_binding_and_is_innermost_parent_pat_struct(pat: &Pat<'_>, hir_id: Hi
|
|||
true
|
||||
},
|
||||
});
|
||||
(span, is_innermost_parent_pat_struct)
|
||||
(binding, is_innermost_parent_pat_struct)
|
||||
}
|
||||
|
||||
/// Builds a chain of reference-manipulation method calls (e.g., `.as_ref()`, `.as_mut()`,
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue