mirror of
https://github.com/rust-lang/rust-clippy
synced 2024-11-10 07:04:18 +00:00
Merge commit '3c06e0b1ce003912f8fe0536d3a7fe22558e38cf' into clippyup
This commit is contained in:
parent
eceedd9c8b
commit
cf8a67d9ad
114 changed files with 2508 additions and 775 deletions
153
CHANGELOG.md
153
CHANGELOG.md
|
@ -6,11 +6,156 @@ document.
|
|||
|
||||
## Unreleased / Beta / In Rust Nightly
|
||||
|
||||
[d822110d...master](https://github.com/rust-lang/rust-clippy/compare/d822110d...master)
|
||||
[7f27e2e7...master](https://github.com/rust-lang/rust-clippy/compare/7f27e2e7...master)
|
||||
|
||||
## Rust 1.68
|
||||
|
||||
Current stable, released 2023-03-09
|
||||
|
||||
[d822110d...7f27e2e7](https://github.com/rust-lang/rust-clippy/compare/d822110d...7f27e2e7)
|
||||
|
||||
### New Lints
|
||||
|
||||
* [`permissions_set_readonly_false`]
|
||||
[#10063](https://github.com/rust-lang/rust-clippy/pull/10063)
|
||||
* [`almost_complete_range`]
|
||||
[#10043](https://github.com/rust-lang/rust-clippy/pull/10043)
|
||||
* [`size_of_ref`]
|
||||
[#10098](https://github.com/rust-lang/rust-clippy/pull/10098)
|
||||
* [`semicolon_outside_block`]
|
||||
[#9826](https://github.com/rust-lang/rust-clippy/pull/9826)
|
||||
* [`semicolon_inside_block`]
|
||||
[#9826](https://github.com/rust-lang/rust-clippy/pull/9826)
|
||||
* [`transmute_null_to_fn`]
|
||||
[#10099](https://github.com/rust-lang/rust-clippy/pull/10099)
|
||||
* [`fn_null_check`]
|
||||
[#10099](https://github.com/rust-lang/rust-clippy/pull/10099)
|
||||
|
||||
### Moves and Deprecations
|
||||
|
||||
* Moved [`manual_clamp`] to `nursery` (Now allow-by-default)
|
||||
[#10101](https://github.com/rust-lang/rust-clippy/pull/10101)
|
||||
* Moved [`mutex_atomic`] to `restriction`
|
||||
[#10115](https://github.com/rust-lang/rust-clippy/pull/10115)
|
||||
* Renamed `derive_hash_xor_eq` to [`derived_hash_with_manual_eq`]
|
||||
[#10184](https://github.com/rust-lang/rust-clippy/pull/10184)
|
||||
|
||||
### Enhancements
|
||||
|
||||
* [`collapsible_str_replace`]: Now takes MSRV into consideration. The minimal version is 1.58
|
||||
[#10047](https://github.com/rust-lang/rust-clippy/pull/10047)
|
||||
* [`unused_self`]: No longer lints, if the method body contains a `todo!()` call
|
||||
[#10166](https://github.com/rust-lang/rust-clippy/pull/10166)
|
||||
* [`derivable_impls`]: Now suggests deriving `Default` for enums with default unit variants
|
||||
[#10161](https://github.com/rust-lang/rust-clippy/pull/10161)
|
||||
* [`arithmetic_side_effects`]: Added two new config values
|
||||
`arithmetic-side-effects-allowed-binary` and `arithmetic-side-effects-allowed-unary`
|
||||
to allow operation on user types
|
||||
[#9840](https://github.com/rust-lang/rust-clippy/pull/9840)
|
||||
* [`large_const_arrays`], [`large_stack_arrays`]: avoid integer overflow when calculating
|
||||
total array size
|
||||
[#10103](https://github.com/rust-lang/rust-clippy/pull/10103)
|
||||
* [`indexing_slicing`]: add new config `suppress-restriction-lint-in-const` to enable
|
||||
restriction lints, even if the suggestion might not be applicable
|
||||
[#9920](https://github.com/rust-lang/rust-clippy/pull/9920)
|
||||
* [`needless_borrow`], [`redundant_clone`]: Now track references better and detect more cases
|
||||
[#9701](https://github.com/rust-lang/rust-clippy/pull/9701)
|
||||
* [`derived_hash_with_manual_eq`]: Now allows `#[derive(PartialEq)]` with custom `Hash`
|
||||
implementations
|
||||
[#10184](https://github.com/rust-lang/rust-clippy/pull/10184)
|
||||
* [`manual_is_ascii_check`]: Now detects ranges with `.contains()` calls
|
||||
[#10053](https://github.com/rust-lang/rust-clippy/pull/10053)
|
||||
* [`transmuting_null`]: Now detects `const` pointers to all types
|
||||
[#10099](https://github.com/rust-lang/rust-clippy/pull/10099)
|
||||
* [`needless_return`]: Now detects more cases for returns of owned values
|
||||
[#10110](https://github.com/rust-lang/rust-clippy/pull/10110)
|
||||
|
||||
### False Positive Fixes
|
||||
|
||||
* [`field_reassign_with_default`]: No longer lints cases, where values are initializes from
|
||||
closures capturing struct values
|
||||
[#10143](https://github.com/rust-lang/rust-clippy/pull/10143)
|
||||
* [`seek_to_start_instead_of_rewind`]: No longer lints, if the return of `seek` is used.
|
||||
[#10096](https://github.com/rust-lang/rust-clippy/pull/10096)
|
||||
* [`manual_filter`]: Now ignores if expressions where the else branch has side effects or
|
||||
doesn't return `None`
|
||||
[#10091](https://github.com/rust-lang/rust-clippy/pull/10091)
|
||||
* [`implicit_clone`]: No longer lints if the type doesn't implement clone
|
||||
[#10022](https://github.com/rust-lang/rust-clippy/pull/10022)
|
||||
* [`match_wildcard_for_single_variants`]: No longer lints on wildcards with a guard
|
||||
[#10056](https://github.com/rust-lang/rust-clippy/pull/10056)
|
||||
* [`drop_ref`]: No longer lints idiomatic expression in `match` arms
|
||||
[#10142](https://github.com/rust-lang/rust-clippy/pull/10142)
|
||||
* [`arithmetic_side_effects`]: No longer lints on corner cases with negative number literals
|
||||
[#9867](https://github.com/rust-lang/rust-clippy/pull/9867)
|
||||
* [`string_lit_as_bytes`]: No longer lints in scrutinies of `match` statements
|
||||
[#10012](https://github.com/rust-lang/rust-clippy/pull/10012)
|
||||
* [`manual_assert`]: No longer lints in `else if` statements
|
||||
[#10013](https://github.com/rust-lang/rust-clippy/pull/10013)
|
||||
* [`needless_return`]: don't lint when using `do yeet`
|
||||
[#10109](https://github.com/rust-lang/rust-clippy/pull/10109)
|
||||
* All lints: No longer lint in enum discriminant values when the suggestion won't work in a
|
||||
const context
|
||||
[#10008](https://github.com/rust-lang/rust-clippy/pull/10008)
|
||||
* [`single_element_loop`]: No longer lints, if the loop contains a `break` or `continue`
|
||||
[#10162](https://github.com/rust-lang/rust-clippy/pull/10162)
|
||||
* [`uninlined_format_args`]: No longer suggests inlining arguments in `assert!` and
|
||||
`debug_assert!` macros before 2021 edition
|
||||
[#10055](https://github.com/rust-lang/rust-clippy/pull/10055)
|
||||
* [`explicit_counter_loop`]: No longer ignores counter changes after `continue` expressions
|
||||
[#10094](https://github.com/rust-lang/rust-clippy/pull/10094)
|
||||
* [`from_over_into`]: No longer lints on opaque types
|
||||
[#9982](https://github.com/rust-lang/rust-clippy/pull/9982)
|
||||
* [`expl_impl_clone_on_copy`]: No longer lints on `#[repr(packed)]` structs with generic
|
||||
parameters
|
||||
[#10189](https://github.com/rust-lang/rust-clippy/pull/10189)
|
||||
|
||||
### Suggestion Fixes/Improvements
|
||||
|
||||
* [`zero_ptr`]: Now suggests `core::` paths for `no_std` crates
|
||||
[#10023](https://github.com/rust-lang/rust-clippy/pull/10023)
|
||||
* [`useless_conversion`]: Now suggests removing calls to `into_iter()` on an expression
|
||||
implementing `Iterator`
|
||||
[#10020](https://github.com/rust-lang/rust-clippy/pull/10020)
|
||||
* [`box_default`]: The suggestion now uses short paths
|
||||
[#10153](https://github.com/rust-lang/rust-clippy/pull/10153)
|
||||
* [`default_trait_access`], [`clone_on_copy`]: The suggestion now uses short paths
|
||||
[#10160](https://github.com/rust-lang/rust-clippy/pull/10160)
|
||||
* [`comparison_to_empty`]: The suggestion now removes unused deref operations
|
||||
[#9962](https://github.com/rust-lang/rust-clippy/pull/9962)
|
||||
* [`manual_let_else`]: Suggestions for or-patterns now include required brackets.
|
||||
[#9966](https://github.com/rust-lang/rust-clippy/pull/9966)
|
||||
* [`match_single_binding`]: suggestion no longer introduces unneeded semicolons
|
||||
[#10060](https://github.com/rust-lang/rust-clippy/pull/10060)
|
||||
* [`case_sensitive_file_extension_comparisons`]: Now displays a suggestion with `Path`
|
||||
[#10107](https://github.com/rust-lang/rust-clippy/pull/10107)
|
||||
* [`empty_structs_with_brackets`]: The suggestion is no longer machine applicable, to avoid
|
||||
errors when accessing struct fields
|
||||
[#10141](https://github.com/rust-lang/rust-clippy/pull/10141)
|
||||
* [`identity_op`]: Removes borrows in the suggestion when needed
|
||||
[#10004](https://github.com/rust-lang/rust-clippy/pull/10004)
|
||||
* [`suboptimal_flops`]: The suggestion now includes parentheses when required
|
||||
[#10113](https://github.com/rust-lang/rust-clippy/pull/10113)
|
||||
* [`iter_kv_map`]: Now handles `mut` and reference annotations in the suggestion
|
||||
[#10159](https://github.com/rust-lang/rust-clippy/pull/10159)
|
||||
* [`redundant_static_lifetimes`]: The suggestion no longer removes `mut` from references
|
||||
[#10006](https://github.com/rust-lang/rust-clippy/pull/10006)
|
||||
|
||||
### ICE Fixes
|
||||
|
||||
* [`new_ret_no_self`]: Now avoids a stack overflow for `impl Trait` types
|
||||
[#10086](https://github.com/rust-lang/rust-clippy/pull/10086)
|
||||
* [`unnecessary_to_owned`]: Now handles compiler generated notes better
|
||||
[#10027](https://github.com/rust-lang/rust-clippy/pull/10027)
|
||||
|
||||
### Others
|
||||
|
||||
* `SYSROOT` and `--sysroot` can now be set at the same time
|
||||
[#10149](https://github.com/rust-lang/rust-clippy/pull/10149)
|
||||
|
||||
## Rust 1.67
|
||||
|
||||
Current stable, released 2023-01-26
|
||||
Released 2023-01-26
|
||||
|
||||
[4f142aa1...d822110d](https://github.com/rust-lang/rust-clippy/compare/4f142aa1...d822110d)
|
||||
|
||||
|
@ -4307,6 +4452,7 @@ Released 2018-09-13
|
|||
[`collapsible_if`]: https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_if
|
||||
[`collapsible_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_match
|
||||
[`collapsible_str_replace`]: https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_str_replace
|
||||
[`collection_is_never_read`]: https://rust-lang.github.io/rust-clippy/master/index.html#collection_is_never_read
|
||||
[`comparison_chain`]: https://rust-lang.github.io/rust-clippy/master/index.html#comparison_chain
|
||||
[`comparison_to_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#comparison_to_empty
|
||||
[`const_static_lifetime`]: https://rust-lang.github.io/rust-clippy/master/index.html#const_static_lifetime
|
||||
|
@ -4497,6 +4643,7 @@ Released 2018-09-13
|
|||
[`let_underscore_must_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_must_use
|
||||
[`let_underscore_untyped`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_untyped
|
||||
[`let_unit_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_unit_value
|
||||
[`let_with_type_underscore`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_with_type_underscore
|
||||
[`linkedlist`]: https://rust-lang.github.io/rust-clippy/master/index.html#linkedlist
|
||||
[`logic_bug`]: https://rust-lang.github.io/rust-clippy/master/index.html#logic_bug
|
||||
[`lossy_float_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#lossy_float_literal
|
||||
|
@ -4560,6 +4707,7 @@ Released 2018-09-13
|
|||
[`mismatching_type_param_order`]: https://rust-lang.github.io/rust-clippy/master/index.html#mismatching_type_param_order
|
||||
[`misnamed_getters`]: https://rust-lang.github.io/rust-clippy/master/index.html#misnamed_getters
|
||||
[`misrefactored_assign_op`]: https://rust-lang.github.io/rust-clippy/master/index.html#misrefactored_assign_op
|
||||
[`missing_assert_message`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_assert_message
|
||||
[`missing_const_for_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_const_for_fn
|
||||
[`missing_docs_in_private_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_docs_in_private_items
|
||||
[`missing_enforced_import_renames`]: https://rust-lang.github.io/rust-clippy/master/index.html#missing_enforced_import_renames
|
||||
|
@ -4689,6 +4837,7 @@ Released 2018-09-13
|
|||
[`read_zero_byte_vec`]: https://rust-lang.github.io/rust-clippy/master/index.html#read_zero_byte_vec
|
||||
[`recursive_format_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#recursive_format_impl
|
||||
[`redundant_allocation`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_allocation
|
||||
[`redundant_async_block`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_async_block
|
||||
[`redundant_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_clone
|
||||
[`redundant_closure`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure
|
||||
[`redundant_closure_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure_call
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "clippy"
|
||||
version = "0.1.69"
|
||||
version = "0.1.70"
|
||||
description = "A bunch of helpful lints to avoid common pitfalls in Rust"
|
||||
repository = "https://github.com/rust-lang/rust-clippy"
|
||||
readme = "README.md"
|
||||
|
|
|
@ -68,13 +68,13 @@ The second part of the motivation is clippy's dependence on unstable
|
|||
compiler-internal data structures. Clippy lints are currently written against
|
||||
the compiler's AST / HIR which means that even small changes in these data
|
||||
structures might break a lot of lints. The second goal of this RFC is to **make
|
||||
lints independant of the compiler's AST / HIR data structures**.
|
||||
lints independent of the compiler's AST / HIR data structures**.
|
||||
|
||||
# Approach
|
||||
|
||||
A lot of complexity in writing lints currently seems to come from having to
|
||||
manually implement the matching logic (see code samples above). It's an
|
||||
imparative style that describes *how* to match a syntax tree node instead of
|
||||
imperative style that describes *how* to match a syntax tree node instead of
|
||||
specifying *what* should be matched against declaratively. In other areas, it's
|
||||
common to use declarative patterns to describe desired information and let the
|
||||
implementation do the actual matching. A well-known example of this approach are
|
||||
|
@ -270,7 +270,7 @@ pattern!{
|
|||
// matches if expressions that **may or may not** have an else block
|
||||
// Attn: `If(_, _, _)` matches only ifs that **have** an else block
|
||||
//
|
||||
// | if with else block | if witout else block
|
||||
// | if with else block | if without else block
|
||||
// If(_, _, _) | match | no match
|
||||
// If(_, _, _?) | match | match
|
||||
// If(_, _, ()) | no match | match
|
||||
|
@ -568,7 +568,7 @@ another example, `Array( Lit(_)* )` is a valid pattern because the parameter of
|
|||
|
||||
## The IsMatch Trait
|
||||
|
||||
The pattern syntax and the *PatternTree* are independant of specific syntax tree
|
||||
The pattern syntax and the *PatternTree* are independent of specific syntax tree
|
||||
implementations (rust ast / hir, syn, ...). When looking at the different
|
||||
pattern examples in the previous sections, it can be seen that the patterns
|
||||
don't contain any information specific to a certain syntax tree implementation.
|
||||
|
@ -717,7 +717,7 @@ if false {
|
|||
#### Problems
|
||||
|
||||
Extending Rust syntax (which is quite complex by itself) with additional syntax
|
||||
needed for specifying patterns (alternations, sequences, repetisions, named
|
||||
needed for specifying patterns (alternations, sequences, repetitions, named
|
||||
submatches, ...) might become difficult to read and really hard to parse
|
||||
properly.
|
||||
|
||||
|
@ -858,7 +858,7 @@ would be evaluated as soon as the `Block(_)#then` was matched.
|
|||
Another idea in this area would be to introduce a syntax for backreferences.
|
||||
They could be used to require that multiple parts of a pattern should match the
|
||||
same value. For example, the `assign_op_pattern` lint that searches for `a = a
|
||||
op b` and recommends changing it to `a op= b` requires that both occurrances of
|
||||
op b` and recommends changing it to `a op= b` requires that both occurrences of
|
||||
`a` are the same. Using `=#...` as syntax for backreferences, the lint could be
|
||||
implemented like this:
|
||||
|
||||
|
@ -882,7 +882,7 @@ least two return statements" could be a practical addition.
|
|||
For patterns like "a literal that is not a boolean literal" one currently needs
|
||||
to list all alternatives except the boolean case. Introducing a negation
|
||||
operator that allows to write `Lit(!Bool(_))` might be a good idea. This pattern
|
||||
would be eqivalent to `Lit( Char(_) | Int(_) )` (given that currently only three
|
||||
would be equivalent to `Lit( Char(_) | Int(_) )` (given that currently only three
|
||||
literal types are implemented).
|
||||
|
||||
#### Functional composition
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "clippy_lints"
|
||||
version = "0.1.69"
|
||||
version = "0.1.70"
|
||||
description = "A bunch of helpful lints to avoid common pitfalls in Rust"
|
||||
repository = "https://github.com/rust-lang/rust-clippy"
|
||||
readme = "README.md"
|
||||
|
|
|
@ -24,7 +24,7 @@ declare_clippy_lint! {
|
|||
/// ```rust
|
||||
/// let _ = 'a'..='z';
|
||||
/// ```
|
||||
#[clippy::version = "1.63.0"]
|
||||
#[clippy::version = "1.68.0"]
|
||||
pub ALMOST_COMPLETE_RANGE,
|
||||
suspicious,
|
||||
"almost complete range"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::msrvs::{self, Msrv};
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::source::snippet_with_context;
|
||||
use clippy_utils::{match_def_path, paths};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
|
@ -34,6 +34,8 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>,
|
|||
if let ExprKind::Path(ref qpath) = fun.kind;
|
||||
if let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id();
|
||||
if let Some(rpk) = raw_parts_kind(cx, fun_def_id);
|
||||
let ctxt = expr.span.ctxt();
|
||||
if cast_expr.span.ctxt() == ctxt;
|
||||
then {
|
||||
let func = match rpk {
|
||||
RawPartsKind::Immutable => "from_raw_parts",
|
||||
|
@ -41,8 +43,8 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>,
|
|||
};
|
||||
let span = expr.span;
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let ptr = snippet_with_applicability(cx, ptr_arg.span, "ptr", &mut applicability);
|
||||
let len = snippet_with_applicability(cx, len_arg.span, "len", &mut applicability);
|
||||
let ptr = snippet_with_context(cx, ptr_arg.span, ctxt, "ptr", &mut applicability).0;
|
||||
let len = snippet_with_context(cx, len_arg.span, ctxt, "len", &mut applicability).0;
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
CAST_SLICE_FROM_RAW_PARTS,
|
||||
|
|
122
clippy_lints/src/collection_is_never_read.rs
Normal file
122
clippy_lints/src/collection_is_never_read.rs
Normal file
|
@ -0,0 +1,122 @@
|
|||
use clippy_utils::diagnostics::span_lint;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::visitors::for_each_expr_with_closures;
|
||||
use clippy_utils::{get_enclosing_block, get_parent_node, path_to_local_id};
|
||||
use core::ops::ControlFlow;
|
||||
use rustc_hir::{Block, ExprKind, HirId, Local, Node, PatKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::Symbol;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks for collections that are never queried.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// Putting effort into constructing a collection but then never querying it might indicate that
|
||||
/// the author forgot to do whatever they intended to do with the collection. Example: Clone
|
||||
/// a vector, sort it for iteration, but then mistakenly iterate the original vector
|
||||
/// instead.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```rust
|
||||
/// # let samples = vec![3, 1, 2];
|
||||
/// let mut sorted_samples = samples.clone();
|
||||
/// sorted_samples.sort();
|
||||
/// for sample in &samples { // Oops, meant to use `sorted_samples`.
|
||||
/// println!("{sample}");
|
||||
/// }
|
||||
/// ```
|
||||
/// Use instead:
|
||||
/// ```rust
|
||||
/// # let samples = vec![3, 1, 2];
|
||||
/// let mut sorted_samples = samples.clone();
|
||||
/// sorted_samples.sort();
|
||||
/// for sample in &sorted_samples {
|
||||
/// println!("{sample}");
|
||||
/// }
|
||||
/// ```
|
||||
#[clippy::version = "1.69.0"]
|
||||
pub COLLECTION_IS_NEVER_READ,
|
||||
nursery,
|
||||
"a collection is never queried"
|
||||
}
|
||||
declare_lint_pass!(CollectionIsNeverRead => [COLLECTION_IS_NEVER_READ]);
|
||||
|
||||
static COLLECTIONS: [Symbol; 10] = [
|
||||
sym::BTreeMap,
|
||||
sym::BTreeSet,
|
||||
sym::BinaryHeap,
|
||||
sym::HashMap,
|
||||
sym::HashSet,
|
||||
sym::LinkedList,
|
||||
sym::Option,
|
||||
sym::String,
|
||||
sym::Vec,
|
||||
sym::VecDeque,
|
||||
];
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for CollectionIsNeverRead {
|
||||
fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>) {
|
||||
// Look for local variables whose type is a container. Search surrounding bock for read access.
|
||||
let ty = cx.typeck_results().pat_ty(local.pat);
|
||||
if COLLECTIONS.iter().any(|&sym| is_type_diagnostic_item(cx, ty, sym))
|
||||
&& let PatKind::Binding(_, local_id, _, _) = local.pat.kind
|
||||
&& let Some(enclosing_block) = get_enclosing_block(cx, local.hir_id)
|
||||
&& has_no_read_access(cx, local_id, enclosing_block)
|
||||
{
|
||||
span_lint(cx, COLLECTION_IS_NEVER_READ, local.span, "collection is never read");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn has_no_read_access<'tcx>(cx: &LateContext<'tcx>, id: HirId, block: &'tcx Block<'tcx>) -> bool {
|
||||
let mut has_access = false;
|
||||
let mut has_read_access = false;
|
||||
|
||||
// Inspect all expressions and sub-expressions in the block.
|
||||
for_each_expr_with_closures(cx, block, |expr| {
|
||||
// Ignore expressions that are not simply `id`.
|
||||
if !path_to_local_id(expr, id) {
|
||||
return ControlFlow::Continue(());
|
||||
}
|
||||
|
||||
// `id` is being accessed. Investigate if it's a read access.
|
||||
has_access = true;
|
||||
|
||||
// `id` appearing in the left-hand side of an assignment is not a read access:
|
||||
//
|
||||
// id = ...; // Not reading `id`.
|
||||
if let Some(Node::Expr(parent)) = get_parent_node(cx.tcx, expr.hir_id)
|
||||
&& let ExprKind::Assign(lhs, ..) = parent.kind
|
||||
&& path_to_local_id(lhs, id)
|
||||
{
|
||||
return ControlFlow::Continue(());
|
||||
}
|
||||
|
||||
// Method call on `id` in a statement ignores any return value, so it's not a read access:
|
||||
//
|
||||
// id.foo(...); // Not reading `id`.
|
||||
//
|
||||
// Only assuming this for "official" methods defined on the type. For methods defined in extension
|
||||
// traits (identified as local, based on the orphan rule), pessimistically assume that they might
|
||||
// have side effects, so consider them a read.
|
||||
if let Some(Node::Expr(parent)) = get_parent_node(cx.tcx, expr.hir_id)
|
||||
&& let ExprKind::MethodCall(_, receiver, _, _) = parent.kind
|
||||
&& path_to_local_id(receiver, id)
|
||||
&& let Some(Node::Stmt(..)) = get_parent_node(cx.tcx, parent.hir_id)
|
||||
&& let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(parent.hir_id)
|
||||
&& !method_def_id.is_local()
|
||||
{
|
||||
return ControlFlow::Continue(());
|
||||
}
|
||||
|
||||
// Any other access to `id` is a read access. Stop searching.
|
||||
has_read_access = true;
|
||||
ControlFlow::Break(())
|
||||
});
|
||||
|
||||
// Ignore collections that have no access at all. Other lints should catch them.
|
||||
has_access && !has_read_access
|
||||
}
|
|
@ -92,6 +92,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
|
|||
crate::cognitive_complexity::COGNITIVE_COMPLEXITY_INFO,
|
||||
crate::collapsible_if::COLLAPSIBLE_ELSE_IF_INFO,
|
||||
crate::collapsible_if::COLLAPSIBLE_IF_INFO,
|
||||
crate::collection_is_never_read::COLLECTION_IS_NEVER_READ_INFO,
|
||||
crate::comparison_chain::COMPARISON_CHAIN_INFO,
|
||||
crate::copies::BRANCHES_SHARING_CODE_INFO,
|
||||
crate::copies::IFS_SAME_COND_INFO,
|
||||
|
@ -226,6 +227,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
|
|||
crate::let_underscore::LET_UNDERSCORE_LOCK_INFO,
|
||||
crate::let_underscore::LET_UNDERSCORE_MUST_USE_INFO,
|
||||
crate::let_underscore::LET_UNDERSCORE_UNTYPED_INFO,
|
||||
crate::let_with_type_underscore::LET_WITH_TYPE_UNDERSCORE_INFO,
|
||||
crate::lifetimes::EXTRA_UNUSED_LIFETIMES_INFO,
|
||||
crate::lifetimes::NEEDLESS_LIFETIMES_INFO,
|
||||
crate::literal_representation::DECIMAL_LITERAL_REPRESENTATION_INFO,
|
||||
|
@ -416,6 +418,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
|
|||
crate::misc_early::UNSEPARATED_LITERAL_SUFFIX_INFO,
|
||||
crate::misc_early::ZERO_PREFIXED_LITERAL_INFO,
|
||||
crate::mismatching_type_param_order::MISMATCHING_TYPE_PARAM_ORDER_INFO,
|
||||
crate::missing_assert_message::MISSING_ASSERT_MESSAGE_INFO,
|
||||
crate::missing_const_for_fn::MISSING_CONST_FOR_FN_INFO,
|
||||
crate::missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS_INFO,
|
||||
crate::missing_enforced_import_rename::MISSING_ENFORCED_IMPORT_RENAMES_INFO,
|
||||
|
@ -517,6 +520,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
|
|||
crate::ranges::REVERSED_EMPTY_RANGES_INFO,
|
||||
crate::rc_clone_in_vec_init::RC_CLONE_IN_VEC_INIT_INFO,
|
||||
crate::read_zero_byte_vec::READ_ZERO_BYTE_VEC_INFO,
|
||||
crate::redundant_async_block::REDUNDANT_ASYNC_BLOCK_INFO,
|
||||
crate::redundant_clone::REDUNDANT_CLONE_INFO,
|
||||
crate::redundant_closure_call::REDUNDANT_CLOSURE_CALL_INFO,
|
||||
crate::redundant_else::REDUNDANT_ELSE_INFO,
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::last_path_segment;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::source::snippet_with_context;
|
||||
use clippy_utils::{match_def_path, paths};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{def, Expr, ExprKind, GenericArg, QPath, TyKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::SyntaxContext;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
|
@ -38,9 +39,11 @@ impl<'tcx> LateLintPass<'tcx> for DefaultIterEmpty {
|
|||
&& let QPath::Resolved(None, path) = ty_path
|
||||
&& let def::Res::Def(_, def_id) = &path.res
|
||||
&& match_def_path(cx, *def_id, &paths::ITER_EMPTY)
|
||||
&& let ctxt = expr.span.ctxt()
|
||||
&& ty.span.ctxt() == ctxt
|
||||
{
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let sugg = make_sugg(cx, ty_path, &mut applicability);
|
||||
let sugg = make_sugg(cx, ty_path, ctxt, &mut applicability);
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
DEFAULT_INSTEAD_OF_ITER_EMPTY,
|
||||
|
@ -54,14 +57,19 @@ impl<'tcx> LateLintPass<'tcx> for DefaultIterEmpty {
|
|||
}
|
||||
}
|
||||
|
||||
fn make_sugg(cx: &LateContext<'_>, ty_path: &rustc_hir::QPath<'_>, applicability: &mut Applicability) -> String {
|
||||
fn make_sugg(
|
||||
cx: &LateContext<'_>,
|
||||
ty_path: &rustc_hir::QPath<'_>,
|
||||
ctxt: SyntaxContext,
|
||||
applicability: &mut Applicability,
|
||||
) -> String {
|
||||
if let Some(last) = last_path_segment(ty_path).args
|
||||
&& let Some(iter_ty) = last.args.iter().find_map(|arg| match arg {
|
||||
GenericArg::Type(ty) => Some(ty),
|
||||
_ => None,
|
||||
})
|
||||
{
|
||||
format!("std::iter::empty::<{}>()", snippet_with_applicability(cx, iter_ty.span, "..", applicability))
|
||||
format!("std::iter::empty::<{}>()", snippet_with_context(cx, iter_ty.span, ctxt, "..", applicability).0)
|
||||
} else {
|
||||
"std::iter::empty()".to_owned()
|
||||
}
|
||||
|
|
|
@ -1357,10 +1357,10 @@ fn replace_types<'tcx>(
|
|||
&& let Some(term_ty) = projection_predicate.term.ty()
|
||||
&& let ty::Param(term_param_ty) = term_ty.kind()
|
||||
{
|
||||
let item_def_id = projection_predicate.projection_ty.def_id;
|
||||
let assoc_item = cx.tcx.associated_item(item_def_id);
|
||||
let projection = cx.tcx
|
||||
.mk_projection(assoc_item.def_id, cx.tcx.mk_substs_trait(new_ty, []));
|
||||
let projection = cx.tcx.mk_ty_from_kind(ty::Alias(
|
||||
ty::Projection,
|
||||
projection_predicate.projection_ty.with_self_ty(cx.tcx, new_ty),
|
||||
));
|
||||
|
||||
if let Ok(projected_ty) = cx.tcx.try_normalize_erasing_regions(cx.param_env, projection)
|
||||
&& substs[term_param_ty.index as usize] != ty::GenericArg::from(projected_ty)
|
||||
|
|
|
@ -8,7 +8,7 @@ use rustc_hir::{
|
|||
Body, Expr, ExprKind, GenericArg, Impl, ImplItemKind, Item, ItemKind, Node, PathSegment, QPath, Ty, TyKind,
|
||||
};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty::AdtDef;
|
||||
use rustc_middle::ty::{Adt, AdtDef, SubstsRef};
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_span::sym;
|
||||
|
||||
|
@ -81,13 +81,18 @@ fn check_struct<'tcx>(
|
|||
self_ty: &Ty<'_>,
|
||||
func_expr: &Expr<'_>,
|
||||
adt_def: AdtDef<'_>,
|
||||
substs: SubstsRef<'_>,
|
||||
) {
|
||||
if let TyKind::Path(QPath::Resolved(_, p)) = self_ty.kind {
|
||||
if let Some(PathSegment { args: Some(a), .. }) = p.segments.last() {
|
||||
for arg in a.args {
|
||||
if !matches!(arg, GenericArg::Lifetime(_)) {
|
||||
return;
|
||||
}
|
||||
if let Some(PathSegment { args, .. }) = p.segments.last() {
|
||||
let args = args.map(|a| a.args).unwrap_or(&[]);
|
||||
|
||||
// substs contains the generic parameters of the type declaration, while args contains the arguments
|
||||
// used at instantiation time. If both len are not equal, it means that some parameters were not
|
||||
// provided (which means that the default values were used); in this case we will not risk
|
||||
// suggesting too broad a rewrite. We won't either if any argument is a type or a const.
|
||||
if substs.len() != args.len() || args.iter().any(|arg| !matches!(arg, GenericArg::Lifetime(_))) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -184,7 +189,7 @@ impl<'tcx> LateLintPass<'tcx> for DerivableImpls {
|
|||
if let Some(Node::ImplItem(impl_item)) = cx.tcx.hir().find(impl_item_hir);
|
||||
if let ImplItemKind::Fn(_, b) = &impl_item.kind;
|
||||
if let Body { value: func_expr, .. } = cx.tcx.hir().body(*b);
|
||||
if let Some(adt_def) = cx.tcx.type_of(item.owner_id).subst_identity().ty_adt_def();
|
||||
if let &Adt(adt_def, substs) = cx.tcx.type_of(item.owner_id).subst_identity().kind();
|
||||
if let attrs = cx.tcx.hir().attrs(item.hir_id());
|
||||
if !attrs.iter().any(|attr| attr.doc_str().is_some());
|
||||
if let child_attrs = cx.tcx.hir().attrs(impl_item_hir);
|
||||
|
@ -192,7 +197,7 @@ impl<'tcx> LateLintPass<'tcx> for DerivableImpls {
|
|||
|
||||
then {
|
||||
if adt_def.is_struct() {
|
||||
check_struct(cx, item, self_ty, func_expr, adt_def);
|
||||
check_struct(cx, item, self_ty, func_expr, adt_def, substs);
|
||||
} else if adt_def.is_enum() && self.msrv.meets(msrvs::DEFAULT_ENUM_ATTRIBUTE) {
|
||||
check_enum(cx, item, func_expr, adt_def);
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ declare_clippy_lint! {
|
|||
///
|
||||
/// ### Why is this bad?
|
||||
/// Exit terminates the program at the location it is called. For unrecoverable
|
||||
/// errors `panics` should be used to provide a stacktrace and potentualy other
|
||||
/// errors `panics` should be used to provide a stacktrace and potentially other
|
||||
/// information. A normal termination or one with an error code should happen in
|
||||
/// the main function.
|
||||
///
|
||||
|
|
|
@ -25,7 +25,7 @@ declare_clippy_lint! {
|
|||
///
|
||||
/// if fn_ptr.is_none() { ... }
|
||||
/// ```
|
||||
#[clippy::version = "1.67.0"]
|
||||
#[clippy::version = "1.68.0"]
|
||||
pub FN_NULL_CHECK,
|
||||
correctness,
|
||||
"`fn()` type assumed to be nullable"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::macros::{root_macro_call_first_node, FormatArgsExpn};
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::source::snippet_with_context;
|
||||
use clippy_utils::sugg::Sugg;
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
|
@ -84,9 +84,9 @@ impl<'tcx> LateLintPass<'tcx> for UselessFormat {
|
|||
_ => false,
|
||||
};
|
||||
let sugg = if is_new_string {
|
||||
snippet_with_applicability(cx, value.span, "..", &mut applicability).into_owned()
|
||||
snippet_with_context(cx, value.span, call_site.ctxt(), "..", &mut applicability).0.into_owned()
|
||||
} else {
|
||||
let sugg = Sugg::hir_with_applicability(cx, value, "<arg>", &mut applicability);
|
||||
let sugg = Sugg::hir_with_context(cx, value, call_site.ctxt(), "<arg>", &mut applicability);
|
||||
format!("{}.to_string()", sugg.maybe_par())
|
||||
};
|
||||
span_useless_format(cx, call_site, sugg, applicability);
|
||||
|
|
|
@ -22,7 +22,7 @@ pub(super) fn check_fn<'tcx>(cx: &LateContext<'_>, kind: &'tcx FnKind<'_>, body:
|
|||
if let Some(gen_span) = generics.span_for_param_suggestion() {
|
||||
diag.span_suggestion_with_style(
|
||||
gen_span,
|
||||
"add a type paremeter",
|
||||
"add a type parameter",
|
||||
format!(", {{ /* Generic name */ }}: {}", ¶m.name.ident().as_str()[5..]),
|
||||
rustc_errors::Applicability::HasPlaceholders,
|
||||
rustc_errors::SuggestionStyle::ShowAlways,
|
||||
|
@ -35,7 +35,7 @@ pub(super) fn check_fn<'tcx>(cx: &LateContext<'_>, kind: &'tcx FnKind<'_>, body:
|
|||
ident.span.ctxt(),
|
||||
ident.span.parent(),
|
||||
),
|
||||
"add a type paremeter",
|
||||
"add a type parameter",
|
||||
format!("<{{ /* Generic name */ }}: {}>", ¶m.name.ident().as_str()[5..]),
|
||||
rustc_errors::Applicability::HasPlaceholders,
|
||||
rustc_errors::SuggestionStyle::ShowAlways,
|
||||
|
|
|
@ -97,7 +97,7 @@ pub fn check_fn(cx: &LateContext<'_>, kind: FnKind<'_>, decl: &FnDecl<'_>, body:
|
|||
|
||||
let Some(correct_field) = correct_field else {
|
||||
// There is no field corresponding to the getter name.
|
||||
// FIXME: This can be a false positive if the correct field is reachable trought deeper autodereferences than used_field is
|
||||
// FIXME: This can be a false positive if the correct field is reachable through deeper autodereferences than used_field is
|
||||
return;
|
||||
};
|
||||
|
||||
|
|
|
@ -185,7 +185,7 @@ declare_clippy_lint! {
|
|||
/// ### Examples
|
||||
/// ```rust
|
||||
/// // this could be annotated with `#[must_use]`.
|
||||
/// fn id<T>(t: T) -> T { t }
|
||||
/// pub fn id<T>(t: T) -> T { t }
|
||||
/// ```
|
||||
#[clippy::version = "1.40.0"]
|
||||
pub MUST_USE_CANDIDATE,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use clippy_utils::consts::{constant, Constant};
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::get_parent_expr;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::source::snippet_with_context;
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::ast::{LitIntType, LitKind};
|
||||
use rustc_errors::Applicability;
|
||||
|
@ -55,6 +55,9 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingAdd {
|
|||
if let ExprKind::AssignOp(op1, target, value) = ex.kind;
|
||||
let ty = cx.typeck_results().expr_ty(target);
|
||||
if Some(c) == get_int_max(ty);
|
||||
let ctxt = expr.span.ctxt();
|
||||
if ex.span.ctxt() == ctxt;
|
||||
if expr1.span.ctxt() == ctxt;
|
||||
if clippy_utils::SpanlessEq::new(cx).eq_expr(l, target);
|
||||
if BinOpKind::Add == op1.node;
|
||||
if let ExprKind::Lit(ref lit) = value.kind;
|
||||
|
@ -62,8 +65,15 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingAdd {
|
|||
if block.expr.is_none();
|
||||
then {
|
||||
let mut app = Applicability::MachineApplicable;
|
||||
let code = snippet_with_applicability(cx, target.span, "_", &mut app);
|
||||
let sugg = if let Some(parent) = get_parent_expr(cx, expr) && let ExprKind::If(_cond, _then, Some(else_)) = parent.kind && else_.hir_id == expr.hir_id {format!("{{{code} = {code}.saturating_add(1); }}")} else {format!("{code} = {code}.saturating_add(1);")};
|
||||
let code = snippet_with_context(cx, target.span, ctxt, "_", &mut app).0;
|
||||
let sugg = if let Some(parent) = get_parent_expr(cx, expr)
|
||||
&& let ExprKind::If(_cond, _then, Some(else_)) = parent.kind
|
||||
&& else_.hir_id == expr.hir_id
|
||||
{
|
||||
format!("{{{code} = {code}.saturating_add(1); }}")
|
||||
} else {
|
||||
format!("{code} = {code}.saturating_add(1);")
|
||||
};
|
||||
span_lint_and_sugg(cx, IMPLICIT_SATURATING_ADD, expr.span, "manual saturating add detected", "use instead", sugg, app);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use clippy_utils::diagnostics::{self, span_lint_and_sugg};
|
||||
use clippy_utils::msrvs::{self, Msrv};
|
||||
use clippy_utils::source;
|
||||
use clippy_utils::source::snippet_with_context;
|
||||
use clippy_utils::sugg::Sugg;
|
||||
use clippy_utils::ty;
|
||||
use rustc_errors::Applicability;
|
||||
|
@ -161,14 +161,9 @@ fn print_unchecked_duration_subtraction_sugg(
|
|||
) {
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
|
||||
let left_expr =
|
||||
source::snippet_with_applicability(cx, left_expr.span, "std::time::Instant::now()", &mut applicability);
|
||||
let right_expr = source::snippet_with_applicability(
|
||||
cx,
|
||||
right_expr.span,
|
||||
"std::time::Duration::from_secs(1)",
|
||||
&mut applicability,
|
||||
);
|
||||
let ctxt = expr.span.ctxt();
|
||||
let left_expr = snippet_with_context(cx, left_expr.span, ctxt, "<instant>", &mut applicability).0;
|
||||
let right_expr = snippet_with_context(cx, right_expr.span, ctxt, "<duration>", &mut applicability).0;
|
||||
|
||||
diagnostics::span_lint_and_sugg(
|
||||
cx,
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::{get_item_name, get_parent_as_impl, is_lint_allowed, peel_ref_operators};
|
||||
use clippy_utils::source::snippet_with_context;
|
||||
use clippy_utils::{get_item_name, get_parent_as_impl, is_lint_allowed, peel_ref_operators, sugg::Sugg};
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::ast::LitKind;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::def_id::DefIdSet;
|
||||
use rustc_hir::{
|
||||
def_id::DefId, AssocItemKind, BinOpKind, Expr, ExprKind, FnRetTy, ImplItem, ImplItemKind, ImplicitSelfKind, Item,
|
||||
ItemKind, Mutability, Node, TraitItemRef, TyKind, UnOp,
|
||||
def::Res, def_id::DefId, lang_items::LangItem, AssocItemKind, BinOpKind, Expr, ExprKind, FnRetTy, GenericArg,
|
||||
GenericBound, ImplItem, ImplItemKind, ImplicitSelfKind, Item, ItemKind, Mutability, Node, PathSegment, PrimTy,
|
||||
QPath, TraitItemRef, TyKind, TypeBindingKind,
|
||||
};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty::{self, AssocKind, FnSig, Ty};
|
||||
|
@ -16,7 +17,6 @@ use rustc_span::{
|
|||
source_map::{Span, Spanned, Symbol},
|
||||
symbol::sym,
|
||||
};
|
||||
use std::borrow::Cow;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
|
@ -251,33 +251,98 @@ fn check_trait_items(cx: &LateContext<'_>, visited_trait: &Item<'_>, trait_items
|
|||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
enum LenOutput<'tcx> {
|
||||
enum LenOutput {
|
||||
Integral,
|
||||
Option(DefId),
|
||||
Result(DefId, Ty<'tcx>),
|
||||
Result(DefId),
|
||||
}
|
||||
fn parse_len_output<'tcx>(cx: &LateContext<'_>, sig: FnSig<'tcx>) -> Option<LenOutput<'tcx>> {
|
||||
|
||||
fn extract_future_output<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<&'tcx PathSegment<'tcx>> {
|
||||
if let ty::Alias(_, alias_ty) = ty.kind() &&
|
||||
let Some(Node::Item(item)) = cx.tcx.hir().get_if_local(alias_ty.def_id) &&
|
||||
let Item { kind: ItemKind::OpaqueTy(opaque), .. } = item &&
|
||||
opaque.bounds.len() == 1 &&
|
||||
let GenericBound::LangItemTrait(LangItem::Future, _, _, generic_args) = &opaque.bounds[0] &&
|
||||
generic_args.bindings.len() == 1 &&
|
||||
let TypeBindingKind::Equality {
|
||||
term: rustc_hir::Term::Ty(rustc_hir::Ty {kind: TyKind::Path(QPath::Resolved(_, path)), .. }),
|
||||
} = &generic_args.bindings[0].kind &&
|
||||
path.segments.len() == 1 {
|
||||
return Some(&path.segments[0]);
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
fn is_first_generic_integral<'tcx>(segment: &'tcx PathSegment<'tcx>) -> bool {
|
||||
if let Some(generic_args) = segment.args {
|
||||
if generic_args.args.is_empty() {
|
||||
return false;
|
||||
}
|
||||
let arg = &generic_args.args[0];
|
||||
if let GenericArg::Type(rustc_hir::Ty {
|
||||
kind: TyKind::Path(QPath::Resolved(_, path)),
|
||||
..
|
||||
}) = arg
|
||||
{
|
||||
let segments = &path.segments;
|
||||
let segment = &segments[0];
|
||||
let res = &segment.res;
|
||||
if matches!(res, Res::PrimTy(PrimTy::Uint(_))) || matches!(res, Res::PrimTy(PrimTy::Int(_))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
fn parse_len_output<'tcx>(cx: &LateContext<'tcx>, sig: FnSig<'tcx>) -> Option<LenOutput> {
|
||||
if let Some(segment) = extract_future_output(cx, sig.output()) {
|
||||
let res = segment.res;
|
||||
|
||||
if matches!(res, Res::PrimTy(PrimTy::Uint(_))) || matches!(res, Res::PrimTy(PrimTy::Int(_))) {
|
||||
return Some(LenOutput::Integral);
|
||||
}
|
||||
|
||||
if let Res::Def(_, def_id) = res {
|
||||
if cx.tcx.is_diagnostic_item(sym::Option, def_id) && is_first_generic_integral(segment) {
|
||||
return Some(LenOutput::Option(def_id));
|
||||
} else if cx.tcx.is_diagnostic_item(sym::Result, def_id) && is_first_generic_integral(segment) {
|
||||
return Some(LenOutput::Result(def_id));
|
||||
}
|
||||
}
|
||||
|
||||
return None;
|
||||
}
|
||||
|
||||
match *sig.output().kind() {
|
||||
ty::Int(_) | ty::Uint(_) => Some(LenOutput::Integral),
|
||||
ty::Adt(adt, subs) if cx.tcx.is_diagnostic_item(sym::Option, adt.did()) => {
|
||||
subs.type_at(0).is_integral().then(|| LenOutput::Option(adt.did()))
|
||||
},
|
||||
ty::Adt(adt, subs) if cx.tcx.is_diagnostic_item(sym::Result, adt.did()) => subs
|
||||
.type_at(0)
|
||||
.is_integral()
|
||||
.then(|| LenOutput::Result(adt.did(), subs.type_at(1))),
|
||||
ty::Adt(adt, subs) if cx.tcx.is_diagnostic_item(sym::Result, adt.did()) => {
|
||||
subs.type_at(0).is_integral().then(|| LenOutput::Result(adt.did()))
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> LenOutput<'tcx> {
|
||||
fn matches_is_empty_output(self, ty: Ty<'tcx>) -> bool {
|
||||
impl LenOutput {
|
||||
fn matches_is_empty_output<'tcx>(self, cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
|
||||
if let Some(segment) = extract_future_output(cx, ty) {
|
||||
return match (self, segment.res) {
|
||||
(_, Res::PrimTy(PrimTy::Bool)) => true,
|
||||
(Self::Option(_), Res::Def(_, def_id)) if cx.tcx.is_diagnostic_item(sym::Option, def_id) => true,
|
||||
(Self::Result(_), Res::Def(_, def_id)) if cx.tcx.is_diagnostic_item(sym::Result, def_id) => true,
|
||||
_ => false,
|
||||
};
|
||||
}
|
||||
|
||||
match (self, ty.kind()) {
|
||||
(_, &ty::Bool) => true,
|
||||
(Self::Option(id), &ty::Adt(adt, subs)) if id == adt.did() => subs.type_at(0).is_bool(),
|
||||
(Self::Result(id, err_ty), &ty::Adt(adt, subs)) if id == adt.did() => {
|
||||
subs.type_at(0).is_bool() && subs.type_at(1) == err_ty
|
||||
},
|
||||
(Self::Result(id), &ty::Adt(adt, subs)) if id == adt.did() => subs.type_at(0).is_bool(),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
@ -301,9 +366,14 @@ impl<'tcx> LenOutput<'tcx> {
|
|||
}
|
||||
|
||||
/// Checks if the given signature matches the expectations for `is_empty`
|
||||
fn check_is_empty_sig<'tcx>(sig: FnSig<'tcx>, self_kind: ImplicitSelfKind, len_output: LenOutput<'tcx>) -> bool {
|
||||
fn check_is_empty_sig<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
sig: FnSig<'tcx>,
|
||||
self_kind: ImplicitSelfKind,
|
||||
len_output: LenOutput,
|
||||
) -> bool {
|
||||
match &**sig.inputs_and_output {
|
||||
[arg, res] if len_output.matches_is_empty_output(*res) => {
|
||||
[arg, res] if len_output.matches_is_empty_output(cx, *res) => {
|
||||
matches!(
|
||||
(arg.kind(), self_kind),
|
||||
(ty::Ref(_, _, Mutability::Not), ImplicitSelfKind::ImmRef)
|
||||
|
@ -315,11 +385,11 @@ fn check_is_empty_sig<'tcx>(sig: FnSig<'tcx>, self_kind: ImplicitSelfKind, len_o
|
|||
}
|
||||
|
||||
/// Checks if the given type has an `is_empty` method with the appropriate signature.
|
||||
fn check_for_is_empty<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
fn check_for_is_empty(
|
||||
cx: &LateContext<'_>,
|
||||
span: Span,
|
||||
self_kind: ImplicitSelfKind,
|
||||
output: LenOutput<'tcx>,
|
||||
output: LenOutput,
|
||||
impl_ty: DefId,
|
||||
item_name: Symbol,
|
||||
item_kind: &str,
|
||||
|
@ -352,6 +422,7 @@ fn check_for_is_empty<'tcx>(
|
|||
Some(is_empty)
|
||||
if !(is_empty.fn_has_self_parameter
|
||||
&& check_is_empty_sig(
|
||||
cx,
|
||||
cx.tcx.fn_sig(is_empty.def_id).subst_identity().skip_binder(),
|
||||
self_kind,
|
||||
output,
|
||||
|
@ -431,7 +502,7 @@ fn check_len(
|
|||
&format!("using `{op}is_empty` is clearer and more explicit"),
|
||||
format!(
|
||||
"{op}{}.is_empty()",
|
||||
snippet_with_applicability(cx, receiver.span, "_", &mut applicability)
|
||||
snippet_with_context(cx, receiver.span, span.ctxt(), "_", &mut applicability).0,
|
||||
),
|
||||
applicability,
|
||||
);
|
||||
|
@ -444,13 +515,7 @@ fn check_empty_expr(cx: &LateContext<'_>, span: Span, lit1: &Expr<'_>, lit2: &Ex
|
|||
let mut applicability = Applicability::MachineApplicable;
|
||||
|
||||
let lit1 = peel_ref_operators(cx, lit1);
|
||||
let mut lit_str = snippet_with_applicability(cx, lit1.span, "_", &mut applicability);
|
||||
|
||||
// Wrap the expression in parentheses if it's a deref expression. Otherwise operator precedence will
|
||||
// cause the code to dereference boolean(won't compile).
|
||||
if let ExprKind::Unary(UnOp::Deref, _) = lit1.kind {
|
||||
lit_str = Cow::from(format!("({lit_str})"));
|
||||
}
|
||||
let lit_str = Sugg::hir_with_context(cx, lit1, span.ctxt(), "_", &mut applicability).maybe_par();
|
||||
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
|
|
|
@ -124,7 +124,7 @@ declare_clippy_lint! {
|
|||
/// ```
|
||||
#[clippy::version = "1.69.0"]
|
||||
pub LET_UNDERSCORE_UNTYPED,
|
||||
pedantic,
|
||||
restriction,
|
||||
"non-binding `let` without a type annotation"
|
||||
}
|
||||
|
||||
|
|
45
clippy_lints/src/let_with_type_underscore.rs
Normal file
45
clippy_lints/src/let_with_type_underscore.rs
Normal file
|
@ -0,0 +1,45 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use rustc_hir::*;
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Detects when a variable is declared with an explicit type of `_`.
|
||||
/// ### Why is this bad?
|
||||
/// It adds noise, `: _` provides zero clarity or utility.
|
||||
/// ### Example
|
||||
/// ```rust,ignore
|
||||
/// let my_number: _ = 1;
|
||||
/// ```
|
||||
/// Use instead:
|
||||
/// ```rust,ignore
|
||||
/// let my_number = 1;
|
||||
/// ```
|
||||
#[clippy::version = "1.69.0"]
|
||||
pub LET_WITH_TYPE_UNDERSCORE,
|
||||
complexity,
|
||||
"unneeded underscore type (`_`) in a variable declaration"
|
||||
}
|
||||
declare_lint_pass!(UnderscoreTyped => [LET_WITH_TYPE_UNDERSCORE]);
|
||||
|
||||
impl LateLintPass<'_> for UnderscoreTyped {
|
||||
fn check_local<'tcx>(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>) {
|
||||
if_chain! {
|
||||
if !in_external_macro(cx.tcx.sess, local.span);
|
||||
if let Some(ty) = local.ty; // Ensure that it has a type defined
|
||||
if let TyKind::Infer = &ty.kind; // that type is '_'
|
||||
if local.span.ctxt() == ty.span.ctxt();
|
||||
then {
|
||||
span_lint_and_help(cx,
|
||||
LET_WITH_TYPE_UNDERSCORE,
|
||||
local.span,
|
||||
"variable declared with type underscore",
|
||||
Some(ty.span.with_lo(local.pat.span.hi())),
|
||||
"remove the explicit type `_` declaration"
|
||||
)
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
|
@ -87,6 +87,7 @@ mod casts;
|
|||
mod checked_conversions;
|
||||
mod cognitive_complexity;
|
||||
mod collapsible_if;
|
||||
mod collection_is_never_read;
|
||||
mod comparison_chain;
|
||||
mod copies;
|
||||
mod copy_iterator;
|
||||
|
@ -166,6 +167,7 @@ mod large_stack_arrays;
|
|||
mod len_zero;
|
||||
mod let_if_seq;
|
||||
mod let_underscore;
|
||||
mod let_with_type_underscore;
|
||||
mod lifetimes;
|
||||
mod literal_representation;
|
||||
mod loops;
|
||||
|
@ -192,6 +194,7 @@ mod minmax;
|
|||
mod misc;
|
||||
mod misc_early;
|
||||
mod mismatching_type_param_order;
|
||||
mod missing_assert_message;
|
||||
mod missing_const_for_fn;
|
||||
mod missing_doc;
|
||||
mod missing_enforced_import_rename;
|
||||
|
@ -249,6 +252,7 @@ mod question_mark_used;
|
|||
mod ranges;
|
||||
mod rc_clone_in_vec_init;
|
||||
mod read_zero_byte_vec;
|
||||
mod redundant_async_block;
|
||||
mod redundant_clone;
|
||||
mod redundant_closure_call;
|
||||
mod redundant_else;
|
||||
|
@ -533,6 +537,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
.collect(),
|
||||
))
|
||||
});
|
||||
store.register_early_pass(|| Box::new(utils::format_args_collector::FormatArgsCollector));
|
||||
store.register_late_pass(|_| Box::new(utils::dump_hir::DumpHir));
|
||||
store.register_late_pass(|_| Box::new(utils::author::Author));
|
||||
let await_holding_invalid_types = conf.await_holding_invalid_types.clone();
|
||||
|
@ -924,6 +929,10 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
))
|
||||
});
|
||||
store.register_late_pass(|_| Box::new(no_mangle_with_rust_abi::NoMangleWithRustAbi));
|
||||
store.register_late_pass(|_| Box::new(collection_is_never_read::CollectionIsNeverRead));
|
||||
store.register_late_pass(|_| Box::new(missing_assert_message::MissingAssertMessage));
|
||||
store.register_early_pass(|| Box::new(redundant_async_block::RedundantAsyncBlock));
|
||||
store.register_late_pass(|_| Box::new(let_with_type_underscore::UnderscoreTyped));
|
||||
// add lints here, do not remove this comment, it's used in `new_lint`
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::get_parent_expr;
|
||||
use clippy_utils::msrvs::{self, Msrv};
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::source::snippet_with_context;
|
||||
use rustc_ast::ast::LitKind;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{BinOpKind, Expr, ExprKind, GenericArg, QPath};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_span::sym;
|
||||
|
@ -55,13 +56,17 @@ impl<'tcx> LateLintPass<'tcx> for ManualBits {
|
|||
if_chain! {
|
||||
if let ExprKind::Binary(bin_op, left_expr, right_expr) = expr.kind;
|
||||
if let BinOpKind::Mul = &bin_op.node;
|
||||
if !in_external_macro(cx.sess(), expr.span);
|
||||
let ctxt = expr.span.ctxt();
|
||||
if left_expr.span.ctxt() == ctxt;
|
||||
if right_expr.span.ctxt() == ctxt;
|
||||
if let Some((real_ty, resolved_ty, other_expr)) = get_one_size_of_ty(cx, left_expr, right_expr);
|
||||
if matches!(resolved_ty.kind(), ty::Int(_) | ty::Uint(_));
|
||||
if let ExprKind::Lit(lit) = &other_expr.kind;
|
||||
if let LitKind::Int(8, _) = lit.node;
|
||||
then {
|
||||
let mut app = Applicability::MachineApplicable;
|
||||
let ty_snip = snippet_with_applicability(cx, real_ty.span, "..", &mut app);
|
||||
let ty_snip = snippet_with_context(cx, real_ty.span, ctxt, "..", &mut app).0;
|
||||
let sugg = create_sugg(cx, expr, format!("{ty_snip}::BITS"));
|
||||
|
||||
span_lint_and_sugg(
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use clippy_utils::msrvs::{self, Msrv};
|
||||
use clippy_utils::{diagnostics::span_lint_and_sugg, higher, in_constant, macros::root_macro_call, source::snippet};
|
||||
use clippy_utils::{diagnostics::span_lint_and_sugg, higher, in_constant, macros::root_macro_call, sugg::Sugg};
|
||||
use rustc_ast::ast::RangeLimits;
|
||||
use rustc_ast::LitKind::{Byte, Char};
|
||||
use rustc_errors::Applicability;
|
||||
|
@ -115,15 +115,8 @@ fn check_is_ascii(cx: &LateContext<'_>, span: Span, recv: &Expr<'_>, range: &Cha
|
|||
CharRange::Otherwise => None,
|
||||
} {
|
||||
let default_snip = "..";
|
||||
// `snippet_with_applicability` may set applicability to `MaybeIncorrect` for
|
||||
// macro span, so we check applicability manually by comparing `recv` is not default.
|
||||
let recv = snippet(cx, recv.span, default_snip);
|
||||
|
||||
let applicability = if recv == default_snip {
|
||||
Applicability::HasPlaceholders
|
||||
} else {
|
||||
Applicability::MachineApplicable
|
||||
};
|
||||
let mut app = Applicability::MachineApplicable;
|
||||
let recv = Sugg::hir_with_context(cx, recv, span.ctxt(), default_snip, &mut app).maybe_par();
|
||||
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
|
@ -132,7 +125,7 @@ fn check_is_ascii(cx: &LateContext<'_>, span: Span, recv: &Expr<'_>, range: &Cha
|
|||
"manual check for common ascii range",
|
||||
"try",
|
||||
format!("{recv}.{sugg}()"),
|
||||
applicability,
|
||||
app,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use clippy_utils::consts::{constant_full_int, FullInt};
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::msrvs::{self, Msrv};
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::source::snippet_with_context;
|
||||
use clippy_utils::{in_constant, path_to_local};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{BinOpKind, Expr, ExprKind, Node, TyKind};
|
||||
|
@ -60,12 +60,16 @@ impl<'tcx> LateLintPass<'tcx> for ManualRemEuclid {
|
|||
return;
|
||||
}
|
||||
|
||||
// (x % c + c) % c
|
||||
if let ExprKind::Binary(op1, expr1, right) = expr.kind
|
||||
&& op1.node == BinOpKind::Rem
|
||||
&& let ctxt = expr.span.ctxt()
|
||||
&& expr1.span.ctxt() == ctxt
|
||||
&& let Some(const1) = check_for_unsigned_int_constant(cx, right)
|
||||
&& let ExprKind::Binary(op2, left, right) = expr1.kind
|
||||
&& op2.node == BinOpKind::Add
|
||||
&& let Some((const2, expr2)) = check_for_either_unsigned_int_constant(cx, left, right)
|
||||
&& expr2.span.ctxt() == ctxt
|
||||
&& let ExprKind::Binary(op3, expr3, right) = expr2.kind
|
||||
&& op3.node == BinOpKind::Rem
|
||||
&& let Some(const3) = check_for_unsigned_int_constant(cx, right)
|
||||
|
@ -86,7 +90,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualRemEuclid {
|
|||
};
|
||||
|
||||
let mut app = Applicability::MachineApplicable;
|
||||
let rem_of = snippet_with_applicability(cx, expr3.span, "_", &mut app);
|
||||
let rem_of = snippet_with_context(cx, expr3.span, ctxt, "_", &mut app).0;
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
MANUAL_REM_EUCLID,
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::higher;
|
||||
use clippy_utils::method_chain_args;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::is_res_lang_ctor;
|
||||
use clippy_utils::source::snippet_with_context;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, ExprKind, PatKind, QPath};
|
||||
use rustc_hir::{Expr, ExprKind, LangItem, PatKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::sym;
|
||||
|
@ -58,17 +58,18 @@ impl<'tcx> LateLintPass<'tcx> for MatchResultOk {
|
|||
};
|
||||
|
||||
if_chain! {
|
||||
if let ExprKind::MethodCall(ok_path, result_types_0, ..) = let_expr.kind; //check is expr.ok() has type Result<T,E>.ok(, _)
|
||||
if let PatKind::TupleStruct(QPath::Resolved(_, x), y, _) = let_pat.kind; //get operation
|
||||
if method_chain_args(let_expr, &["ok"]).is_some(); //test to see if using ok() method use std::marker::Sized;
|
||||
if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(result_types_0), sym::Result);
|
||||
if rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_path(x, false)) == "Some";
|
||||
|
||||
if let ExprKind::MethodCall(ok_path, recv, [], ..) = let_expr.kind; //check is expr.ok() has type Result<T,E>.ok(, _)
|
||||
if let PatKind::TupleStruct(ref pat_path, [ok_pat], _) = let_pat.kind; //get operation
|
||||
if ok_path.ident.as_str() == "ok";
|
||||
if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result);
|
||||
if is_res_lang_ctor(cx, cx.qpath_res(pat_path, let_pat.hir_id), LangItem::OptionSome);
|
||||
let ctxt = expr.span.ctxt();
|
||||
if let_expr.span.ctxt() == ctxt;
|
||||
if let_pat.span.ctxt() == ctxt;
|
||||
then {
|
||||
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let some_expr_string = snippet_with_applicability(cx, y[0].span, "", &mut applicability);
|
||||
let trimmed_ok = snippet_with_applicability(cx, let_expr.span.until(ok_path.ident.span), "", &mut applicability);
|
||||
let some_expr_string = snippet_with_context(cx, ok_pat.span, ctxt, "", &mut applicability).0;
|
||||
let trimmed_ok = snippet_with_context(cx, recv.span, ctxt, "", &mut applicability).0;
|
||||
let sugg = format!(
|
||||
"{ifwhile} let Ok({some_expr_string}) = {}",
|
||||
trimmed_ok.trim().trim_end_matches('.'),
|
||||
|
|
|
@ -925,7 +925,7 @@ declare_clippy_lint! {
|
|||
#[clippy::version = "1.66.0"]
|
||||
pub MANUAL_FILTER,
|
||||
complexity,
|
||||
"reimplentation of `filter`"
|
||||
"reimplementation of `filter`"
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
|
|
|
@ -340,8 +340,9 @@ declare_clippy_lint! {
|
|||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks for methods with certain name prefixes and which
|
||||
/// doesn't match how self is taken. The actual rules are:
|
||||
/// Checks for methods with certain name prefixes or suffixes, and which
|
||||
/// do not adhere to standard conventions regarding how `self` is taken.
|
||||
/// The actual rules are:
|
||||
///
|
||||
/// |Prefix |Postfix |`self` taken | `self` type |
|
||||
/// |-------|------------|-------------------------------|--------------|
|
||||
|
|
82
clippy_lints/src/missing_assert_message.rs
Normal file
82
clippy_lints/src/missing_assert_message.rs
Normal file
|
@ -0,0 +1,82 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use clippy_utils::macros::{find_assert_args, find_assert_eq_args, root_macro_call_first_node, PanicExpn};
|
||||
use clippy_utils::{is_in_cfg_test, is_in_test_function};
|
||||
use rustc_hir::Expr;
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::sym;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks assertions without a custom panic message.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// Without a good custom message, it'd be hard to understand what went wrong when the assertion fails.
|
||||
/// A good custom message should be more about why the failure of the assertion is problematic
|
||||
/// and not what is failed because the assertion already conveys that.
|
||||
///
|
||||
/// ### Known problems
|
||||
/// This lint cannot check the quality of the custom panic messages.
|
||||
/// Hence, you can suppress this lint simply by adding placeholder messages
|
||||
/// like "assertion failed". However, we recommend coming up with good messages
|
||||
/// that provide useful information instead of placeholder messages that
|
||||
/// don't provide any extra information.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```rust
|
||||
/// # struct Service { ready: bool }
|
||||
/// fn call(service: Service) {
|
||||
/// assert!(service.ready);
|
||||
/// }
|
||||
/// ```
|
||||
/// Use instead:
|
||||
/// ```rust
|
||||
/// # struct Service { ready: bool }
|
||||
/// fn call(service: Service) {
|
||||
/// assert!(service.ready, "`service.poll_ready()` must be called first to ensure that service is ready to receive requests");
|
||||
/// }
|
||||
/// ```
|
||||
#[clippy::version = "1.69.0"]
|
||||
pub MISSING_ASSERT_MESSAGE,
|
||||
restriction,
|
||||
"checks assertions without a custom panic message"
|
||||
}
|
||||
|
||||
declare_lint_pass!(MissingAssertMessage => [MISSING_ASSERT_MESSAGE]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for MissingAssertMessage {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
let Some(macro_call) = root_macro_call_first_node(cx, expr) else { return };
|
||||
let single_argument = match cx.tcx.get_diagnostic_name(macro_call.def_id) {
|
||||
Some(sym::assert_macro | sym::debug_assert_macro) => true,
|
||||
Some(
|
||||
sym::assert_eq_macro | sym::assert_ne_macro | sym::debug_assert_eq_macro | sym::debug_assert_ne_macro,
|
||||
) => false,
|
||||
_ => return,
|
||||
};
|
||||
|
||||
// This lint would be very noisy in tests, so just ignore if we're in test context
|
||||
if is_in_test_function(cx.tcx, expr.hir_id) || is_in_cfg_test(cx.tcx, expr.hir_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
let panic_expn = if single_argument {
|
||||
let Some((_, panic_expn)) = find_assert_args(cx, expr, macro_call.expn) else { return };
|
||||
panic_expn
|
||||
} else {
|
||||
let Some((_, _, panic_expn)) = find_assert_eq_args(cx, expr, macro_call.expn) else { return };
|
||||
panic_expn
|
||||
};
|
||||
|
||||
if let PanicExpn::Empty = panic_expn {
|
||||
span_lint_and_help(
|
||||
cx,
|
||||
MISSING_ASSERT_MESSAGE,
|
||||
macro_call.span,
|
||||
"assert without any message",
|
||||
None,
|
||||
"consider describing why the failing assert is problematic",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,10 +8,10 @@
|
|||
use clippy_utils::attrs::is_doc_hidden;
|
||||
use clippy_utils::diagnostics::span_lint;
|
||||
use clippy_utils::is_from_proc_macro;
|
||||
use hir::def_id::LocalDefId;
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::ast::{self, MetaItem, MetaItemKind};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
use rustc_middle::ty::Visibility;
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
|
@ -21,8 +21,7 @@ use rustc_span::sym;
|
|||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Warns if there is missing doc for any documentable item
|
||||
/// (public or private).
|
||||
/// Warns if there is missing doc for any private documentable item
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// Doc is good. *rustc* has a `MISSING_DOCS`
|
||||
|
@ -32,7 +31,7 @@ declare_clippy_lint! {
|
|||
#[clippy::version = "pre 1.29.0"]
|
||||
pub MISSING_DOCS_IN_PRIVATE_ITEMS,
|
||||
restriction,
|
||||
"detects missing documentation for public and private members"
|
||||
"detects missing documentation for private members"
|
||||
}
|
||||
|
||||
pub struct MissingDoc {
|
||||
|
@ -107,11 +106,14 @@ impl MissingDoc {
|
|||
if vis == Visibility::Public || vis != Visibility::Restricted(CRATE_DEF_ID.into()) {
|
||||
return;
|
||||
}
|
||||
} else if def_id != CRATE_DEF_ID && cx.effective_visibilities.is_exported(def_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
let has_doc = attrs
|
||||
.iter()
|
||||
.any(|a| a.doc_str().is_some() || Self::has_include(a.meta()));
|
||||
|
||||
if !has_doc {
|
||||
span_lint(
|
||||
cx,
|
||||
|
|
|
@ -11,6 +11,7 @@ use rustc_ast::Mutability;
|
|||
use rustc_hir as hir;
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_middle::ty;
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::Span;
|
||||
|
||||
|
@ -120,33 +121,15 @@ fn collect_unsafe_exprs<'tcx>(
|
|||
unsafe_ops.push(("raw pointer dereference occurs here", expr.span));
|
||||
},
|
||||
|
||||
ExprKind::Call(path_expr, _) => match path_expr.kind {
|
||||
ExprKind::Path(QPath::Resolved(
|
||||
_,
|
||||
hir::Path {
|
||||
res: Res::Def(kind, def_id),
|
||||
..
|
||||
},
|
||||
)) if kind.is_fn_like() => {
|
||||
let sig = cx.tcx.fn_sig(*def_id);
|
||||
if sig.0.unsafety() == Unsafety::Unsafe {
|
||||
unsafe_ops.push(("unsafe function call occurs here", expr.span));
|
||||
}
|
||||
},
|
||||
|
||||
ExprKind::Path(QPath::TypeRelative(..)) => {
|
||||
if let Some(sig) = cx
|
||||
.typeck_results()
|
||||
.type_dependent_def_id(path_expr.hir_id)
|
||||
.map(|def_id| cx.tcx.fn_sig(def_id))
|
||||
{
|
||||
if sig.0.unsafety() == Unsafety::Unsafe {
|
||||
unsafe_ops.push(("unsafe function call occurs here", expr.span));
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_ => {},
|
||||
ExprKind::Call(path_expr, _) => {
|
||||
let sig = match *cx.typeck_results().expr_ty(path_expr).kind() {
|
||||
ty::FnDef(id, _) => cx.tcx.fn_sig(id).skip_binder(),
|
||||
ty::FnPtr(sig) => sig,
|
||||
_ => return Continue(Descend::Yes),
|
||||
};
|
||||
if sig.unsafety() == Unsafety::Unsafe {
|
||||
unsafe_ops.push(("unsafe function call occurs here", expr.span));
|
||||
}
|
||||
},
|
||||
|
||||
ExprKind::MethodCall(..) => {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use clippy_utils::consts::{self, Constant};
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::source::snippet_with_context;
|
||||
use clippy_utils::sugg::has_enclosing_paren;
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::util::parser::PREC_PREFIX;
|
||||
|
@ -60,8 +60,8 @@ fn check_mul(cx: &LateContext<'_>, span: Span, lit: &Expr<'_>, exp: &Expr<'_>) {
|
|||
|
||||
then {
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let snip = snippet_with_applicability(cx, exp.span, "..", &mut applicability);
|
||||
let suggestion = if exp.precedence().order() < PREC_PREFIX && !has_enclosing_paren(&snip) {
|
||||
let (snip, from_macro) = snippet_with_context(cx, exp.span, span.ctxt(), "..", &mut applicability);
|
||||
let suggestion = if !from_macro && exp.precedence().order() < PREC_PREFIX && !has_enclosing_paren(&snip) {
|
||||
format!("-({snip})")
|
||||
} else {
|
||||
format!("-{snip}")
|
||||
|
|
|
@ -53,6 +53,7 @@ impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions {
|
|||
|| is_type_diagnostic_item(cx, obj_ty, sym::DirBuilder)))
|
||||
|| (path.ident.name == sym!(set_mode) && match_type(cx, obj_ty, &paths::PERMISSIONS));
|
||||
if let ExprKind::Lit(_) = param.kind;
|
||||
if param.span.ctxt() == expr.span.ctxt();
|
||||
|
||||
then {
|
||||
let Some(snip) = snippet_opt(cx, param.span) else {
|
||||
|
@ -71,6 +72,7 @@ impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions {
|
|||
if let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id();
|
||||
if match_def_path(cx, def_id, &paths::PERMISSIONS_FROM_MODE);
|
||||
if let ExprKind::Lit(_) = param.kind;
|
||||
if param.span.ctxt() == expr.span.ctxt();
|
||||
if let Some(snip) = snippet_opt(cx, param.span);
|
||||
if !snip.starts_with("0o");
|
||||
then {
|
||||
|
|
|
@ -143,6 +143,10 @@ impl ArithmeticSideEffects {
|
|||
return;
|
||||
}
|
||||
let has_valid_op = if Self::is_integral(lhs_ty) && Self::is_integral(rhs_ty) {
|
||||
if let hir::BinOpKind::Shl | hir::BinOpKind::Shr = op.node {
|
||||
// At least for integers, shifts are already handled by the CTFE
|
||||
return;
|
||||
}
|
||||
let (actual_lhs, lhs_ref_counter) = peel_hir_expr_refs(lhs);
|
||||
let (actual_rhs, rhs_ref_counter) = peel_hir_expr_refs(rhs);
|
||||
match (
|
||||
|
@ -151,10 +155,13 @@ impl ArithmeticSideEffects {
|
|||
) {
|
||||
(None, None) => false,
|
||||
(None, Some(n)) | (Some(n), None) => match (&op.node, n) {
|
||||
(hir::BinOpKind::Div | hir::BinOpKind::Rem, 0) => false,
|
||||
// Division and module are always valid if applied to non-zero integers
|
||||
(hir::BinOpKind::Div | hir::BinOpKind::Rem, local_n) if local_n != 0 => true,
|
||||
// Addition or subtracting zeros is always a no-op
|
||||
(hir::BinOpKind::Add | hir::BinOpKind::Sub, 0)
|
||||
| (hir::BinOpKind::Div | hir::BinOpKind::Rem, _)
|
||||
| (hir::BinOpKind::Mul, 0 | 1) => true,
|
||||
// Multiplication by 1 or 0 will never overflow
|
||||
| (hir::BinOpKind::Mul, 0 | 1)
|
||||
=> true,
|
||||
_ => false,
|
||||
},
|
||||
(Some(_), Some(_)) => {
|
||||
|
|
|
@ -21,7 +21,7 @@ declare_clippy_lint! {
|
|||
/// let mut permissions = metadata.permissions();
|
||||
/// permissions.set_readonly(false);
|
||||
/// ```
|
||||
#[clippy::version = "1.66.0"]
|
||||
#[clippy::version = "1.68.0"]
|
||||
pub PERMISSIONS_SET_READONLY_FALSE,
|
||||
suspicious,
|
||||
"Checks for calls to `std::fs::Permissions.set_readonly` with argument `false`"
|
||||
|
|
84
clippy_lints/src/redundant_async_block.rs
Normal file
84
clippy_lints/src/redundant_async_block.rs
Normal file
|
@ -0,0 +1,84 @@
|
|||
use clippy_utils::{diagnostics::span_lint_and_sugg, source::snippet};
|
||||
use rustc_ast::ast::*;
|
||||
use rustc_ast::visit::Visitor as AstVisitor;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks for `async` block that only returns `await` on a future.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// It is simpler and more efficient to use the future directly.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```rust
|
||||
/// async fn f() -> i32 {
|
||||
/// 1 + 2
|
||||
/// }
|
||||
///
|
||||
/// let fut = async {
|
||||
/// f().await
|
||||
/// };
|
||||
/// ```
|
||||
/// Use instead:
|
||||
/// ```rust
|
||||
/// async fn f() -> i32 {
|
||||
/// 1 + 2
|
||||
/// }
|
||||
///
|
||||
/// let fut = f();
|
||||
/// ```
|
||||
#[clippy::version = "1.69.0"]
|
||||
pub REDUNDANT_ASYNC_BLOCK,
|
||||
complexity,
|
||||
"`async { future.await }` can be replaced by `future`"
|
||||
}
|
||||
declare_lint_pass!(RedundantAsyncBlock => [REDUNDANT_ASYNC_BLOCK]);
|
||||
|
||||
impl EarlyLintPass for RedundantAsyncBlock {
|
||||
fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
|
||||
if expr.span.from_expansion() {
|
||||
return;
|
||||
}
|
||||
if let ExprKind::Async(_, _, block) = &expr.kind && block.stmts.len() == 1 &&
|
||||
let Some(Stmt { kind: StmtKind::Expr(last), .. }) = block.stmts.last() &&
|
||||
let ExprKind::Await(future) = &last.kind &&
|
||||
!future.span.from_expansion() &&
|
||||
!await_in_expr(future)
|
||||
{
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
REDUNDANT_ASYNC_BLOCK,
|
||||
expr.span,
|
||||
"this async expression only awaits a single future",
|
||||
"you can reduce it to",
|
||||
snippet(cx, future.span, "..").into_owned(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Check whether an expression contains `.await`
|
||||
fn await_in_expr(expr: &Expr) -> bool {
|
||||
let mut detector = AwaitDetector::default();
|
||||
detector.visit_expr(expr);
|
||||
detector.await_found
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct AwaitDetector {
|
||||
await_found: bool,
|
||||
}
|
||||
|
||||
impl<'ast> AstVisitor<'ast> for AwaitDetector {
|
||||
fn visit_expr(&mut self, ex: &'ast Expr) {
|
||||
match (&ex.kind, self.await_found) {
|
||||
(ExprKind::Await(_), _) => self.await_found = true,
|
||||
(_, false) => rustc_ast::visit::walk_expr(self, ex),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -45,7 +45,7 @@ declare_clippy_lint! {
|
|||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[clippy::version = "1.67.0"]
|
||||
#[clippy::version = "1.68.0"]
|
||||
pub SIZE_OF_REF,
|
||||
suspicious,
|
||||
"Argument to `std::mem::size_of_val()` is a double-reference, which is almost certainly unintended"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::source::snippet_with_context;
|
||||
use clippy_utils::sugg::Sugg;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::{can_mut_borrow_both, eq_expr_value, in_constant, std_or_core};
|
||||
|
@ -10,6 +10,7 @@ use rustc_lint::{LateContext, LateLintPass};
|
|||
use rustc_middle::ty;
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_span::SyntaxContext;
|
||||
use rustc_span::{sym, symbol::Ident, Span};
|
||||
|
||||
declare_clippy_lint! {
|
||||
|
@ -80,43 +81,45 @@ impl<'tcx> LateLintPass<'tcx> for Swap {
|
|||
}
|
||||
|
||||
fn generate_swap_warning(cx: &LateContext<'_>, e1: &Expr<'_>, e2: &Expr<'_>, span: Span, is_xor_based: bool) {
|
||||
let ctxt = span.ctxt();
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
|
||||
if !can_mut_borrow_both(cx, e1, e2) {
|
||||
if let ExprKind::Index(lhs1, idx1) = e1.kind {
|
||||
if let ExprKind::Index(lhs2, idx2) = e2.kind {
|
||||
if eq_expr_value(cx, lhs1, lhs2) {
|
||||
let ty = cx.typeck_results().expr_ty(lhs1).peel_refs();
|
||||
if let ExprKind::Index(lhs1, idx1) = e1.kind
|
||||
&& let ExprKind::Index(lhs2, idx2) = e2.kind
|
||||
&& eq_expr_value(cx, lhs1, lhs2)
|
||||
&& e1.span.ctxt() == ctxt
|
||||
&& e2.span.ctxt() == ctxt
|
||||
{
|
||||
let ty = cx.typeck_results().expr_ty(lhs1).peel_refs();
|
||||
|
||||
if matches!(ty.kind(), ty::Slice(_))
|
||||
|| matches!(ty.kind(), ty::Array(_, _))
|
||||
|| is_type_diagnostic_item(cx, ty, sym::Vec)
|
||||
|| is_type_diagnostic_item(cx, ty, sym::VecDeque)
|
||||
{
|
||||
let slice = Sugg::hir_with_applicability(cx, lhs1, "<slice>", &mut applicability);
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
MANUAL_SWAP,
|
||||
span,
|
||||
&format!("this looks like you are swapping elements of `{slice}` manually"),
|
||||
"try",
|
||||
format!(
|
||||
"{}.swap({}, {})",
|
||||
slice.maybe_par(),
|
||||
snippet_with_applicability(cx, idx1.span, "..", &mut applicability),
|
||||
snippet_with_applicability(cx, idx2.span, "..", &mut applicability),
|
||||
),
|
||||
applicability,
|
||||
);
|
||||
}
|
||||
}
|
||||
if matches!(ty.kind(), ty::Slice(_))
|
||||
|| matches!(ty.kind(), ty::Array(_, _))
|
||||
|| is_type_diagnostic_item(cx, ty, sym::Vec)
|
||||
|| is_type_diagnostic_item(cx, ty, sym::VecDeque)
|
||||
{
|
||||
let slice = Sugg::hir_with_applicability(cx, lhs1, "<slice>", &mut applicability);
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
MANUAL_SWAP,
|
||||
span,
|
||||
&format!("this looks like you are swapping elements of `{slice}` manually"),
|
||||
"try",
|
||||
format!(
|
||||
"{}.swap({}, {});",
|
||||
slice.maybe_par(),
|
||||
snippet_with_context(cx, idx1.span, ctxt, "..", &mut applicability).0,
|
||||
snippet_with_context(cx, idx2.span, ctxt, "..", &mut applicability).0,
|
||||
),
|
||||
applicability,
|
||||
);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
let first = Sugg::hir_with_applicability(cx, e1, "..", &mut applicability);
|
||||
let second = Sugg::hir_with_applicability(cx, e2, "..", &mut applicability);
|
||||
let first = Sugg::hir_with_context(cx, e1, ctxt, "..", &mut applicability);
|
||||
let second = Sugg::hir_with_context(cx, e2, ctxt, "..", &mut applicability);
|
||||
let Some(sugg) = std_or_core(cx) else { return };
|
||||
|
||||
span_lint_and_then(
|
||||
|
@ -128,7 +131,7 @@ fn generate_swap_warning(cx: &LateContext<'_>, e1: &Expr<'_>, e2: &Expr<'_>, spa
|
|||
diag.span_suggestion(
|
||||
span,
|
||||
"try",
|
||||
format!("{sugg}::mem::swap({}, {})", first.mut_addr(), second.mut_addr()),
|
||||
format!("{sugg}::mem::swap({}, {});", first.mut_addr(), second.mut_addr()),
|
||||
applicability,
|
||||
);
|
||||
if !is_xor_based {
|
||||
|
@ -144,19 +147,19 @@ fn check_manual_swap(cx: &LateContext<'_>, block: &Block<'_>) {
|
|||
return;
|
||||
}
|
||||
|
||||
for w in block.stmts.windows(3) {
|
||||
for [s1, s2, s3] in block.stmts.array_windows::<3>() {
|
||||
if_chain! {
|
||||
// let t = foo();
|
||||
if let StmtKind::Local(tmp) = w[0].kind;
|
||||
if let StmtKind::Local(tmp) = s1.kind;
|
||||
if let Some(tmp_init) = tmp.init;
|
||||
if let PatKind::Binding(.., ident, None) = tmp.pat.kind;
|
||||
|
||||
// foo() = bar();
|
||||
if let StmtKind::Semi(first) = w[1].kind;
|
||||
if let StmtKind::Semi(first) = s2.kind;
|
||||
if let ExprKind::Assign(lhs1, rhs1, _) = first.kind;
|
||||
|
||||
// bar() = t;
|
||||
if let StmtKind::Semi(second) = w[2].kind;
|
||||
if let StmtKind::Semi(second) = s3.kind;
|
||||
if let ExprKind::Assign(lhs2, rhs2, _) = second.kind;
|
||||
if let ExprKind::Path(QPath::Resolved(None, rhs2)) = rhs2.kind;
|
||||
if rhs2.segments.len() == 1;
|
||||
|
@ -164,8 +167,15 @@ fn check_manual_swap(cx: &LateContext<'_>, block: &Block<'_>) {
|
|||
if ident.name == rhs2.segments[0].ident.name;
|
||||
if eq_expr_value(cx, tmp_init, lhs1);
|
||||
if eq_expr_value(cx, rhs1, lhs2);
|
||||
|
||||
let ctxt = s1.span.ctxt();
|
||||
if s2.span.ctxt() == ctxt;
|
||||
if s3.span.ctxt() == ctxt;
|
||||
if first.span.ctxt() == ctxt;
|
||||
if second.span.ctxt() == ctxt;
|
||||
|
||||
then {
|
||||
let span = w[0].span.to(second.span);
|
||||
let span = s1.span.to(s3.span);
|
||||
generate_swap_warning(cx, lhs1, lhs2, span, false);
|
||||
}
|
||||
}
|
||||
|
@ -246,17 +256,20 @@ fn parse<'a, 'hir>(stmt: &'a Stmt<'hir>) -> Option<(ExprOrIdent<'hir>, &'a Expr<
|
|||
|
||||
/// Implementation of the xor case for `MANUAL_SWAP` lint.
|
||||
fn check_xor_swap(cx: &LateContext<'_>, block: &Block<'_>) {
|
||||
for window in block.stmts.windows(3) {
|
||||
for [s1, s2, s3] in block.stmts.array_windows::<3>() {
|
||||
if_chain! {
|
||||
if let Some((lhs0, rhs0)) = extract_sides_of_xor_assign(&window[0]);
|
||||
if let Some((lhs1, rhs1)) = extract_sides_of_xor_assign(&window[1]);
|
||||
if let Some((lhs2, rhs2)) = extract_sides_of_xor_assign(&window[2]);
|
||||
let ctxt = s1.span.ctxt();
|
||||
if let Some((lhs0, rhs0)) = extract_sides_of_xor_assign(s1, ctxt);
|
||||
if let Some((lhs1, rhs1)) = extract_sides_of_xor_assign(s2, ctxt);
|
||||
if let Some((lhs2, rhs2)) = extract_sides_of_xor_assign(s3, ctxt);
|
||||
if eq_expr_value(cx, lhs0, rhs1);
|
||||
if eq_expr_value(cx, lhs2, rhs1);
|
||||
if eq_expr_value(cx, lhs1, rhs0);
|
||||
if eq_expr_value(cx, lhs1, rhs2);
|
||||
if s2.span.ctxt() == ctxt;
|
||||
if s3.span.ctxt() == ctxt;
|
||||
then {
|
||||
let span = window[0].span.to(window[2].span);
|
||||
let span = s1.span.to(s3.span);
|
||||
generate_swap_warning(cx, lhs0, rhs0, span, true);
|
||||
}
|
||||
};
|
||||
|
@ -264,9 +277,12 @@ fn check_xor_swap(cx: &LateContext<'_>, block: &Block<'_>) {
|
|||
}
|
||||
|
||||
/// Returns the lhs and rhs of an xor assignment statement.
|
||||
fn extract_sides_of_xor_assign<'a, 'hir>(stmt: &'a Stmt<'hir>) -> Option<(&'a Expr<'hir>, &'a Expr<'hir>)> {
|
||||
if let StmtKind::Semi(expr) = stmt.kind {
|
||||
if let ExprKind::AssignOp(
|
||||
fn extract_sides_of_xor_assign<'a, 'hir>(
|
||||
stmt: &'a Stmt<'hir>,
|
||||
ctxt: SyntaxContext,
|
||||
) -> Option<(&'a Expr<'hir>, &'a Expr<'hir>)> {
|
||||
if let StmtKind::Semi(expr) = stmt.kind
|
||||
&& let ExprKind::AssignOp(
|
||||
Spanned {
|
||||
node: BinOpKind::BitXor,
|
||||
..
|
||||
|
@ -274,9 +290,10 @@ fn extract_sides_of_xor_assign<'a, 'hir>(stmt: &'a Stmt<'hir>) -> Option<(&'a Ex
|
|||
lhs,
|
||||
rhs,
|
||||
) = expr.kind
|
||||
{
|
||||
return Some((lhs, rhs));
|
||||
}
|
||||
&& expr.span.ctxt() == ctxt
|
||||
{
|
||||
Some((lhs, rhs))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
None
|
||||
}
|
||||
|
|
|
@ -458,7 +458,7 @@ declare_clippy_lint! {
|
|||
/// ```rust
|
||||
/// let null_fn: Option<fn()> = None;
|
||||
/// ```
|
||||
#[clippy::version = "1.67.0"]
|
||||
#[clippy::version = "1.68.0"]
|
||||
pub TRANSMUTE_NULL_TO_FN,
|
||||
correctness,
|
||||
"transmute results in a null function pointer, which is undefined behavior"
|
||||
|
|
|
@ -5,7 +5,7 @@ use clippy_utils::visitors::{for_each_local_assignment, for_each_value_source};
|
|||
use core::ops::ControlFlow;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::{Expr, ExprKind, HirId, HirIdSet, Local, Node, PatKind, QPath, TyKind};
|
||||
use rustc_hir::{Expr, ExprKind, HirId, HirIdSet, Local, MatchSource, Node, PatKind, QPath, TyKind};
|
||||
use rustc_lint::{LateContext, LintContext};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_middle::ty;
|
||||
|
@ -41,6 +41,10 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, local: &'tcx Local<'_>) {
|
|||
);
|
||||
}
|
||||
} else {
|
||||
if let ExprKind::Match(_, _, MatchSource::AwaitDesugar) = init.kind {
|
||||
return
|
||||
}
|
||||
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
LET_UNIT_VALUE,
|
||||
|
|
|
@ -10,8 +10,8 @@ use rustc_hir::{
|
|||
def::{CtorOf, DefKind, Res},
|
||||
def_id::LocalDefId,
|
||||
intravisit::{walk_inf, walk_ty, Visitor},
|
||||
Expr, ExprKind, FnRetTy, FnSig, GenericArg, HirId, Impl, ImplItemKind, Item, ItemKind, Pat, PatKind, Path, QPath,
|
||||
TyKind,
|
||||
Expr, ExprKind, FnRetTy, FnSig, GenericArg, GenericParam, GenericParamKind, HirId, Impl, ImplItemKind, Item,
|
||||
ItemKind, Pat, PatKind, Path, QPath, Ty, TyKind,
|
||||
};
|
||||
use rustc_hir_analysis::hir_ty_to_ty;
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
|
@ -96,7 +96,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
|
|||
// avoid linting on nested items, we push `StackItem::NoCheck` on the stack to signal, that
|
||||
// we're in an `impl` or nested item, that we don't want to lint
|
||||
let stack_item = if_chain! {
|
||||
if let ItemKind::Impl(Impl { self_ty, .. }) = item.kind;
|
||||
if let ItemKind::Impl(Impl { self_ty, generics,.. }) = item.kind;
|
||||
if let TyKind::Path(QPath::Resolved(_, item_path)) = self_ty.kind;
|
||||
let parameters = &item_path.segments.last().expect(SEGMENTS_MSG).args;
|
||||
if parameters.as_ref().map_or(true, |params| {
|
||||
|
@ -105,10 +105,17 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
|
|||
if !item.span.from_expansion();
|
||||
if !is_from_proc_macro(cx, item); // expensive, should be last check
|
||||
then {
|
||||
// Self cannot be used inside const generic parameters
|
||||
let types_to_skip = generics.params.iter().filter_map(|param| {
|
||||
match param {
|
||||
GenericParam { kind: GenericParamKind::Const { ty: Ty { hir_id, ..}, ..}, ..} => Some(*hir_id),
|
||||
_ => None,
|
||||
}
|
||||
}).chain(std::iter::once(self_ty.hir_id)).collect();
|
||||
StackItem::Check {
|
||||
impl_id: item.owner_id.def_id,
|
||||
in_body: 0,
|
||||
types_to_skip: std::iter::once(self_ty.hir_id).collect(),
|
||||
types_to_skip,
|
||||
}
|
||||
} else {
|
||||
StackItem::NoCheck
|
||||
|
|
|
@ -588,7 +588,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
|
|||
},
|
||||
}
|
||||
},
|
||||
ExprKind::Err(_) => kind!("Err"),
|
||||
ExprKind::Err(_) => kind!("Err(_)"),
|
||||
ExprKind::DropTemps(expr) => {
|
||||
bind!(self, expr);
|
||||
kind!("DropTemps({expr})");
|
||||
|
|
23
clippy_lints/src/utils/format_args_collector.rs
Normal file
23
clippy_lints/src/utils/format_args_collector.rs
Normal file
|
@ -0,0 +1,23 @@
|
|||
use clippy_utils::macros::collect_ast_format_args;
|
||||
use rustc_ast::{Expr, ExprKind};
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Collects [`rustc_ast::FormatArgs`] so that future late passes can call
|
||||
/// [`clippy_utils::macros::find_format_args`]
|
||||
pub FORMAT_ARGS_COLLECTOR,
|
||||
internal_warn,
|
||||
"collects `format_args` AST nodes for use in later lints"
|
||||
}
|
||||
|
||||
declare_lint_pass!(FormatArgsCollector => [FORMAT_ARGS_COLLECTOR]);
|
||||
|
||||
impl EarlyLintPass for FormatArgsCollector {
|
||||
fn check_expr(&mut self, _: &EarlyContext<'_>, expr: &Expr) {
|
||||
if let ExprKind::FormatArgs(args) = &expr.kind {
|
||||
collect_ast_format_args(expr.span, args);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -26,7 +26,7 @@ use rustc_session::{declare_tool_lint, impl_lint_pass};
|
|||
use rustc_span::symbol::Ident;
|
||||
use rustc_span::{sym, Loc, Span, Symbol};
|
||||
use serde::{ser::SerializeStruct, Serialize, Serializer};
|
||||
use std::collections::BinaryHeap;
|
||||
use std::collections::{BTreeSet, BinaryHeap};
|
||||
use std::fmt;
|
||||
use std::fmt::Write as _;
|
||||
use std::fs::{self, OpenOptions};
|
||||
|
@ -264,6 +264,9 @@ struct LintMetadata {
|
|||
/// This field is only used in the output and will only be
|
||||
/// mapped shortly before the actual output.
|
||||
applicability: Option<ApplicabilityInfo>,
|
||||
/// All the past names of lints which have been renamed.
|
||||
#[serde(skip_serializing_if = "BTreeSet::is_empty")]
|
||||
former_ids: BTreeSet<String>,
|
||||
}
|
||||
|
||||
impl LintMetadata {
|
||||
|
@ -283,6 +286,7 @@ impl LintMetadata {
|
|||
version,
|
||||
docs,
|
||||
applicability: None,
|
||||
former_ids: BTreeSet::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -901,6 +905,7 @@ fn collect_renames(lints: &mut Vec<LintMetadata>) {
|
|||
if name == lint_name;
|
||||
if let Some(past_name) = k.strip_prefix(CLIPPY_LINT_GROUP_PREFIX);
|
||||
then {
|
||||
lint.former_ids.insert(past_name.to_owned());
|
||||
writeln!(collected, "* `{past_name}`").unwrap();
|
||||
names.push(past_name.to_string());
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
pub mod author;
|
||||
pub mod conf;
|
||||
pub mod dump_hir;
|
||||
pub mod format_args_collector;
|
||||
#[cfg(feature = "internal")]
|
||||
pub mod internal_lints;
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
|
||||
use clippy_utils::macros::{root_macro_call_first_node, FormatArgsExpn, MacroCall};
|
||||
use clippy_utils::macros::{find_format_args, format_arg_removal_span, root_macro_call_first_node, MacroCall};
|
||||
use clippy_utils::source::{expand_past_previous_comma, snippet_opt};
|
||||
use clippy_utils::{is_in_cfg_test, is_in_test_function};
|
||||
use rustc_ast::LitKind;
|
||||
use rustc_ast::token::LitKind;
|
||||
use rustc_ast::{FormatArgPosition, FormatArgs, FormatArgsPiece, FormatOptions, FormatPlaceholder, FormatTrait};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, ExprKind, HirIdMap, Impl, Item, ItemKind};
|
||||
use rustc_hir::{Expr, Impl, Item, ItemKind};
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_span::{sym, BytePos};
|
||||
|
@ -297,34 +298,40 @@ impl<'tcx> LateLintPass<'tcx> for Write {
|
|||
_ => return,
|
||||
}
|
||||
|
||||
let Some(format_args) = FormatArgsExpn::find_nested(cx, expr, macro_call.expn) else { return };
|
||||
find_format_args(cx, expr, macro_call.expn, |format_args| {
|
||||
// ignore `writeln!(w)` and `write!(v, some_macro!())`
|
||||
if format_args.span.from_expansion() {
|
||||
return;
|
||||
}
|
||||
|
||||
// ignore `writeln!(w)` and `write!(v, some_macro!())`
|
||||
if format_args.format_string.span.from_expansion() {
|
||||
return;
|
||||
}
|
||||
match diag_name {
|
||||
sym::print_macro | sym::eprint_macro | sym::write_macro => {
|
||||
check_newline(cx, format_args, ¯o_call, name);
|
||||
},
|
||||
sym::println_macro | sym::eprintln_macro | sym::writeln_macro => {
|
||||
check_empty_string(cx, format_args, ¯o_call, name);
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
|
||||
match diag_name {
|
||||
sym::print_macro | sym::eprint_macro | sym::write_macro => {
|
||||
check_newline(cx, &format_args, ¯o_call, name);
|
||||
},
|
||||
sym::println_macro | sym::eprintln_macro | sym::writeln_macro => {
|
||||
check_empty_string(cx, &format_args, ¯o_call, name);
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
check_literal(cx, format_args, name);
|
||||
|
||||
check_literal(cx, &format_args, name);
|
||||
|
||||
if !self.in_debug_impl {
|
||||
for arg in &format_args.args {
|
||||
if arg.format.r#trait == sym::Debug {
|
||||
span_lint(cx, USE_DEBUG, arg.span, "use of `Debug`-based formatting");
|
||||
if !self.in_debug_impl {
|
||||
for piece in &format_args.template {
|
||||
if let &FormatArgsPiece::Placeholder(FormatPlaceholder {
|
||||
span: Some(span),
|
||||
format_trait: FormatTrait::Debug,
|
||||
..
|
||||
}) = piece
|
||||
{
|
||||
span_lint(cx, USE_DEBUG, span, "use of `Debug`-based formatting");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn is_debug_impl(cx: &LateContext<'_>, item: &Item<'_>) -> bool {
|
||||
if let ItemKind::Impl(Impl { of_trait: Some(trait_ref), .. }) = &item.kind
|
||||
&& let Some(trait_id) = trait_ref.trait_def_id()
|
||||
|
@ -335,16 +342,18 @@ fn is_debug_impl(cx: &LateContext<'_>, item: &Item<'_>) -> bool {
|
|||
}
|
||||
}
|
||||
|
||||
fn check_newline(cx: &LateContext<'_>, format_args: &FormatArgsExpn<'_>, macro_call: &MacroCall, name: &str) {
|
||||
let format_string_parts = &format_args.format_string.parts;
|
||||
let mut format_string_span = format_args.format_string.span;
|
||||
|
||||
let Some(last) = format_string_parts.last() else { return };
|
||||
fn check_newline(cx: &LateContext<'_>, format_args: &FormatArgs, macro_call: &MacroCall, name: &str) {
|
||||
let Some(FormatArgsPiece::Literal(last)) = format_args.template.last() else { return };
|
||||
|
||||
let count_vertical_whitespace = || {
|
||||
format_string_parts
|
||||
format_args
|
||||
.template
|
||||
.iter()
|
||||
.flat_map(|part| part.as_str().chars())
|
||||
.filter_map(|piece| match piece {
|
||||
FormatArgsPiece::Literal(literal) => Some(literal),
|
||||
FormatArgsPiece::Placeholder(_) => None,
|
||||
})
|
||||
.flat_map(|literal| literal.as_str().chars())
|
||||
.filter(|ch| matches!(ch, '\r' | '\n'))
|
||||
.count()
|
||||
};
|
||||
|
@ -352,10 +361,9 @@ fn check_newline(cx: &LateContext<'_>, format_args: &FormatArgsExpn<'_>, macro_c
|
|||
if last.as_str().ends_with('\n')
|
||||
// ignore format strings with other internal vertical whitespace
|
||||
&& count_vertical_whitespace() == 1
|
||||
|
||||
// ignore trailing arguments: `print!("Issue\n{}", 1265);`
|
||||
&& format_string_parts.len() > format_args.args.len()
|
||||
{
|
||||
let mut format_string_span = format_args.span;
|
||||
|
||||
let lint = if name == "write" {
|
||||
format_string_span = expand_past_previous_comma(cx, format_string_span);
|
||||
|
||||
|
@ -373,7 +381,7 @@ fn check_newline(cx: &LateContext<'_>, format_args: &FormatArgsExpn<'_>, macro_c
|
|||
let name_span = cx.sess().source_map().span_until_char(macro_call.span, '!');
|
||||
let Some(format_snippet) = snippet_opt(cx, format_string_span) else { return };
|
||||
|
||||
if format_string_parts.len() == 1 && last.as_str() == "\n" {
|
||||
if format_args.template.len() == 1 && last.as_str() == "\n" {
|
||||
// print!("\n"), write!(f, "\n")
|
||||
|
||||
diag.multipart_suggestion(
|
||||
|
@ -398,11 +406,12 @@ fn check_newline(cx: &LateContext<'_>, format_args: &FormatArgsExpn<'_>, macro_c
|
|||
}
|
||||
}
|
||||
|
||||
fn check_empty_string(cx: &LateContext<'_>, format_args: &FormatArgsExpn<'_>, macro_call: &MacroCall, name: &str) {
|
||||
if let [part] = &format_args.format_string.parts[..]
|
||||
&& let mut span = format_args.format_string.span
|
||||
&& part.as_str() == "\n"
|
||||
fn check_empty_string(cx: &LateContext<'_>, format_args: &FormatArgs, macro_call: &MacroCall, name: &str) {
|
||||
if let [FormatArgsPiece::Literal(literal)] = &format_args.template[..]
|
||||
&& literal.as_str() == "\n"
|
||||
{
|
||||
let mut span = format_args.span;
|
||||
|
||||
let lint = if name == "writeln" {
|
||||
span = expand_past_previous_comma(cx, span);
|
||||
|
||||
|
@ -428,33 +437,43 @@ fn check_empty_string(cx: &LateContext<'_>, format_args: &FormatArgsExpn<'_>, ma
|
|||
}
|
||||
}
|
||||
|
||||
fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgsExpn<'_>, name: &str) {
|
||||
let mut counts = HirIdMap::<usize>::default();
|
||||
for param in format_args.params() {
|
||||
*counts.entry(param.value.hir_id).or_default() += 1;
|
||||
fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) {
|
||||
let arg_index = |argument: &FormatArgPosition| argument.index.unwrap_or_else(|pos| pos);
|
||||
|
||||
let mut counts = vec![0u32; format_args.arguments.all_args().len()];
|
||||
for piece in &format_args.template {
|
||||
if let FormatArgsPiece::Placeholder(placeholder) = piece {
|
||||
counts[arg_index(&placeholder.argument)] += 1;
|
||||
}
|
||||
}
|
||||
|
||||
for arg in &format_args.args {
|
||||
let value = arg.param.value;
|
||||
|
||||
if counts[&value.hir_id] == 1
|
||||
&& arg.format.is_default()
|
||||
&& let ExprKind::Lit(lit) = &value.kind
|
||||
&& !value.span.from_expansion()
|
||||
&& let Some(value_string) = snippet_opt(cx, value.span)
|
||||
{
|
||||
let (replacement, replace_raw) = match lit.node {
|
||||
LitKind::Str(..) => extract_str_literal(&value_string),
|
||||
LitKind::Char(ch) => (
|
||||
match ch {
|
||||
'"' => "\\\"",
|
||||
'\'' => "'",
|
||||
for piece in &format_args.template {
|
||||
if let FormatArgsPiece::Placeholder(FormatPlaceholder {
|
||||
argument,
|
||||
span: Some(placeholder_span),
|
||||
format_trait: FormatTrait::Display,
|
||||
format_options,
|
||||
}) = piece
|
||||
&& *format_options == FormatOptions::default()
|
||||
&& let index = arg_index(argument)
|
||||
&& counts[index] == 1
|
||||
&& let Some(arg) = format_args.arguments.by_index(index)
|
||||
&& let rustc_ast::ExprKind::Lit(lit) = &arg.expr.kind
|
||||
&& !arg.expr.span.from_expansion()
|
||||
&& let Some(value_string) = snippet_opt(cx, arg.expr.span)
|
||||
{
|
||||
let (replacement, replace_raw) = match lit.kind {
|
||||
LitKind::Str | LitKind::StrRaw(_) => extract_str_literal(&value_string),
|
||||
LitKind::Char => (
|
||||
match lit.symbol.as_str() {
|
||||
"\"" => "\\\"",
|
||||
"\\'" => "'",
|
||||
_ => &value_string[1..value_string.len() - 1],
|
||||
}
|
||||
.to_string(),
|
||||
false,
|
||||
),
|
||||
LitKind::Bool(b) => (b.to_string(), false),
|
||||
LitKind::Bool => (lit.symbol.to_string(), false),
|
||||
_ => continue,
|
||||
};
|
||||
|
||||
|
@ -464,7 +483,9 @@ fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgsExpn<'_>, name: &
|
|||
PRINT_LITERAL
|
||||
};
|
||||
|
||||
let format_string_is_raw = format_args.format_string.style.is_some();
|
||||
let Some(format_string_snippet) = snippet_opt(cx, format_args.span) else { continue };
|
||||
let format_string_is_raw = format_string_snippet.starts_with('r');
|
||||
|
||||
let replacement = match (format_string_is_raw, replace_raw) {
|
||||
(false, false) => Some(replacement),
|
||||
(false, true) => Some(replacement.replace('"', "\\\"").replace('\\', "\\\\")),
|
||||
|
@ -485,23 +506,24 @@ fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgsExpn<'_>, name: &
|
|||
span_lint_and_then(
|
||||
cx,
|
||||
lint,
|
||||
value.span,
|
||||
arg.expr.span,
|
||||
"literal with an empty format string",
|
||||
|diag| {
|
||||
if let Some(replacement) = replacement
|
||||
// `format!("{}", "a")`, `format!("{named}", named = "b")
|
||||
// ~~~~~ ~~~~~~~~~~~~~
|
||||
&& let Some(value_span) = format_args.value_with_prev_comma_span(value.hir_id)
|
||||
&& let Some(removal_span) = format_arg_removal_span(format_args, index)
|
||||
{
|
||||
let replacement = replacement.replace('{', "{{").replace('}', "}}");
|
||||
diag.multipart_suggestion(
|
||||
"try this",
|
||||
vec![(arg.span, replacement), (value_span, String::new())],
|
||||
vec![(*placeholder_span, replacement), (removal_span, String::new())],
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "clippy_utils"
|
||||
version = "0.1.69"
|
||||
version = "0.1.70"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
|
||||
|
|
|
@ -617,7 +617,7 @@ fn item_children_by_name(tcx: TyCtxt<'_>, def_id: DefId, name: Symbol) -> Vec<Re
|
|||
/// Can return multiple resolutions when there are multiple versions of the same crate, e.g.
|
||||
/// `memchr::memchr` could return the functions from both memchr 1.0 and memchr 2.0.
|
||||
///
|
||||
/// Also returns multiple results when there are mulitple paths under the same name e.g. `std::vec`
|
||||
/// Also returns multiple results when there are multiple paths under the same name e.g. `std::vec`
|
||||
/// would have both a [`DefKind::Mod`] and [`DefKind::Macro`].
|
||||
///
|
||||
/// This function is expensive and should be used sparingly.
|
||||
|
|
|
@ -6,6 +6,8 @@ use crate::visitors::{for_each_expr, Descend};
|
|||
use arrayvec::ArrayVec;
|
||||
use itertools::{izip, Either, Itertools};
|
||||
use rustc_ast::ast::LitKind;
|
||||
use rustc_ast::FormatArgs;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_hir::intravisit::{walk_expr, Visitor};
|
||||
use rustc_hir::{self as hir, Expr, ExprField, ExprKind, HirId, LangItem, Node, QPath, TyKind};
|
||||
use rustc_lexer::unescape::unescape_literal;
|
||||
|
@ -15,8 +17,10 @@ use rustc_parse_format::{self as rpf, Alignment};
|
|||
use rustc_span::def_id::DefId;
|
||||
use rustc_span::hygiene::{self, MacroKind, SyntaxContext};
|
||||
use rustc_span::{sym, BytePos, ExpnData, ExpnId, ExpnKind, Pos, Span, SpanData, Symbol};
|
||||
use std::cell::RefCell;
|
||||
use std::iter::{once, zip};
|
||||
use std::ops::ControlFlow;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
|
||||
const FORMAT_MACRO_DIAG_ITEMS: &[Symbol] = &[
|
||||
sym::assert_eq_macro,
|
||||
|
@ -213,6 +217,7 @@ pub fn is_assert_macro(cx: &LateContext<'_>, def_id: DefId) -> bool {
|
|||
matches!(name, sym::assert_macro | sym::debug_assert_macro)
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum PanicExpn<'a> {
|
||||
/// No arguments - `panic!()`
|
||||
Empty,
|
||||
|
@ -226,10 +231,7 @@ pub enum PanicExpn<'a> {
|
|||
|
||||
impl<'a> PanicExpn<'a> {
|
||||
pub fn parse(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<Self> {
|
||||
if !macro_backtrace(expr.span).any(|macro_call| is_panic(cx, macro_call.def_id)) {
|
||||
return None;
|
||||
}
|
||||
let ExprKind::Call(callee, [arg]) = &expr.kind else { return None };
|
||||
let ExprKind::Call(callee, [arg, rest @ ..]) = &expr.kind else { return None };
|
||||
let ExprKind::Path(QPath::Resolved(_, path)) = &callee.kind else { return None };
|
||||
let result = match path.segments.last().unwrap().ident.as_str() {
|
||||
"panic" if arg.span.ctxt() == expr.span.ctxt() => Self::Empty,
|
||||
|
@ -239,6 +241,21 @@ impl<'a> PanicExpn<'a> {
|
|||
Self::Display(e)
|
||||
},
|
||||
"panic_fmt" => Self::Format(FormatArgsExpn::parse(cx, arg)?),
|
||||
// Since Rust 1.52, `assert_{eq,ne}` macros expand to use:
|
||||
// `core::panicking::assert_failed(.., left_val, right_val, None | Some(format_args!(..)));`
|
||||
"assert_failed" => {
|
||||
// It should have 4 arguments in total (we already matched with the first argument,
|
||||
// so we're just checking for 3)
|
||||
if rest.len() != 3 {
|
||||
return None;
|
||||
}
|
||||
// `msg_arg` is either `None` (no custom message) or `Some(format_args!(..))` (custom message)
|
||||
let msg_arg = &rest[2];
|
||||
match msg_arg.kind {
|
||||
ExprKind::Call(_, [fmt_arg]) => Self::Format(FormatArgsExpn::parse(cx, fmt_arg)?),
|
||||
_ => Self::Empty,
|
||||
}
|
||||
},
|
||||
_ => return None,
|
||||
};
|
||||
Some(result)
|
||||
|
@ -251,7 +268,17 @@ pub fn find_assert_args<'a>(
|
|||
expr: &'a Expr<'a>,
|
||||
expn: ExpnId,
|
||||
) -> Option<(&'a Expr<'a>, PanicExpn<'a>)> {
|
||||
find_assert_args_inner(cx, expr, expn).map(|([e], p)| (e, p))
|
||||
find_assert_args_inner(cx, expr, expn).map(|([e], mut p)| {
|
||||
// `assert!(..)` expands to `core::panicking::panic("assertion failed: ...")` (which we map to
|
||||
// `PanicExpn::Str(..)`) and `assert!(.., "..")` expands to
|
||||
// `core::panicking::panic_fmt(format_args!(".."))` (which we map to `PanicExpn::Format(..)`).
|
||||
// So even we got `PanicExpn::Str(..)` that means there is no custom message provided
|
||||
if let PanicExpn::Str(_) = p {
|
||||
p = PanicExpn::Empty;
|
||||
}
|
||||
|
||||
(e, p)
|
||||
})
|
||||
}
|
||||
|
||||
/// Finds the arguments of an `assert_eq!` or `debug_assert_eq!` macro call within the macro
|
||||
|
@ -275,13 +302,12 @@ fn find_assert_args_inner<'a, const N: usize>(
|
|||
Some(inner_name) => find_assert_within_debug_assert(cx, expr, expn, Symbol::intern(inner_name))?,
|
||||
};
|
||||
let mut args = ArrayVec::new();
|
||||
let mut panic_expn = None;
|
||||
let _: Option<!> = for_each_expr(expr, |e| {
|
||||
let panic_expn = for_each_expr(expr, |e| {
|
||||
if args.is_full() {
|
||||
if panic_expn.is_none() && e.span.ctxt() != expr.span.ctxt() {
|
||||
panic_expn = PanicExpn::parse(cx, e);
|
||||
match PanicExpn::parse(cx, e) {
|
||||
Some(expn) => ControlFlow::Break(expn),
|
||||
None => ControlFlow::Continue(Descend::Yes),
|
||||
}
|
||||
ControlFlow::Continue(Descend::from(panic_expn.is_none()))
|
||||
} else if is_assert_arg(cx, e, expn) {
|
||||
args.push(e);
|
||||
ControlFlow::Continue(Descend::No)
|
||||
|
@ -339,6 +365,77 @@ fn is_assert_arg(cx: &LateContext<'_>, expr: &Expr<'_>, assert_expn: ExpnId) ->
|
|||
}
|
||||
}
|
||||
|
||||
thread_local! {
|
||||
/// We preserve the [`FormatArgs`] structs from the early pass for use in the late pass to be
|
||||
/// able to access the many features of a [`LateContext`].
|
||||
///
|
||||
/// A thread local is used because [`FormatArgs`] is `!Send` and `!Sync`, we are making an
|
||||
/// assumption that the early pass the populates the map and the later late passes will all be
|
||||
/// running on the same thread.
|
||||
static AST_FORMAT_ARGS: RefCell<FxHashMap<Span, FormatArgs>> = {
|
||||
static CALLED: AtomicBool = AtomicBool::new(false);
|
||||
debug_assert!(
|
||||
!CALLED.swap(true, Ordering::SeqCst),
|
||||
"incorrect assumption: `AST_FORMAT_ARGS` should only be accessed by a single thread",
|
||||
);
|
||||
|
||||
RefCell::default()
|
||||
};
|
||||
}
|
||||
|
||||
/// Record [`rustc_ast::FormatArgs`] for use in late lint passes, this should only be called by
|
||||
/// `FormatArgsCollector`
|
||||
pub fn collect_ast_format_args(span: Span, format_args: &FormatArgs) {
|
||||
AST_FORMAT_ARGS.with(|ast_format_args| {
|
||||
ast_format_args.borrow_mut().insert(span, format_args.clone());
|
||||
});
|
||||
}
|
||||
|
||||
/// Calls `callback` with an AST [`FormatArgs`] node if one is found
|
||||
pub fn find_format_args(cx: &LateContext<'_>, start: &Expr<'_>, expn_id: ExpnId, callback: impl FnOnce(&FormatArgs)) {
|
||||
let format_args_expr = for_each_expr(start, |expr| {
|
||||
let ctxt = expr.span.ctxt();
|
||||
if ctxt == start.span.ctxt() {
|
||||
ControlFlow::Continue(Descend::Yes)
|
||||
} else if ctxt.outer_expn().is_descendant_of(expn_id)
|
||||
&& macro_backtrace(expr.span)
|
||||
.map(|macro_call| cx.tcx.item_name(macro_call.def_id))
|
||||
.any(|name| matches!(name, sym::const_format_args | sym::format_args | sym::format_args_nl))
|
||||
{
|
||||
ControlFlow::Break(expr)
|
||||
} else {
|
||||
ControlFlow::Continue(Descend::No)
|
||||
}
|
||||
});
|
||||
|
||||
if let Some(format_args_expr) = format_args_expr {
|
||||
AST_FORMAT_ARGS.with(|ast_format_args| {
|
||||
ast_format_args.borrow().get(&format_args_expr.span).map(callback);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the [`Span`] of the value at `index` extended to the previous comma, e.g. for the value
|
||||
/// `10`
|
||||
///
|
||||
/// ```ignore
|
||||
/// format("{}.{}", 10, 11)
|
||||
/// // ^^^^
|
||||
/// ```
|
||||
pub fn format_arg_removal_span(format_args: &FormatArgs, index: usize) -> Option<Span> {
|
||||
let ctxt = format_args.span.ctxt();
|
||||
|
||||
let current = hygiene::walk_chain(format_args.arguments.by_index(index)?.expr.span, ctxt);
|
||||
|
||||
let prev = if index == 0 {
|
||||
format_args.span
|
||||
} else {
|
||||
hygiene::walk_chain(format_args.arguments.by_index(index - 1)?.expr.span, ctxt)
|
||||
};
|
||||
|
||||
Some(current.with_lo(prev.hi()))
|
||||
}
|
||||
|
||||
/// The format string doesn't exist in the HIR, so we reassemble it from source code
|
||||
#[derive(Debug)]
|
||||
pub struct FormatString {
|
||||
|
|
|
@ -16,9 +16,9 @@ use rustc_infer::infer::{
|
|||
use rustc_lint::LateContext;
|
||||
use rustc_middle::mir::interpret::{ConstValue, Scalar};
|
||||
use rustc_middle::ty::{
|
||||
self, AdtDef, AliasTy, AssocKind, Binder, BoundRegion, FnSig, IntTy, List, ParamEnv, Predicate,
|
||||
PredicateKind, Region, RegionKind, SubstsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
|
||||
TypeVisitor, UintTy, VariantDef, VariantDiscr,
|
||||
self, AdtDef, AliasTy, AssocKind, Binder, BoundRegion, FnSig, IntTy, List, ParamEnv, Predicate, PredicateKind,
|
||||
Region, RegionKind, SubstsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
|
||||
UintTy, VariantDef, VariantDiscr,
|
||||
};
|
||||
use rustc_middle::ty::{GenericArg, GenericArgKind};
|
||||
use rustc_span::symbol::Ident;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "declare_clippy_lint"
|
||||
version = "0.1.69"
|
||||
version = "0.1.70"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
|
||||
|
|
|
@ -8,12 +8,16 @@ repository = "https://github.com/rust-lang/rust-clippy"
|
|||
categories = ["development-tools"]
|
||||
edition = "2021"
|
||||
publish = false
|
||||
default-run = "lintcheck"
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.69"
|
||||
cargo_metadata = "0.15.3"
|
||||
clap = "4.1.4"
|
||||
clap = { version = "4.1.8", features = ["derive", "env"] }
|
||||
crates_io_api = "0.8.1"
|
||||
crossbeam-channel = "0.5.6"
|
||||
flate2 = "1.0"
|
||||
indicatif = "0.17.3"
|
||||
rayon = "1.5.1"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0.85"
|
||||
|
@ -24,3 +28,11 @@ walkdir = "2.3"
|
|||
|
||||
[features]
|
||||
deny-warnings = []
|
||||
|
||||
[[bin]]
|
||||
name = "lintcheck"
|
||||
path = "src/main.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "popular-crates"
|
||||
path = "src/popular-crates.rs"
|
||||
|
|
|
@ -25,6 +25,15 @@ the repo root.
|
|||
|
||||
The results will then be saved to `lintcheck-logs/custom_logs.toml`.
|
||||
|
||||
The `custom.toml` file may be built using <https://crates.io> recently most
|
||||
downloaded crates by using the `popular-crates` binary from the `lintcheck`
|
||||
directory. For example, to retrieve the 100 recently most downloaded crates:
|
||||
|
||||
```
|
||||
cargo run --release --bin popular-crates -- -n 100 custom.toml
|
||||
```
|
||||
|
||||
|
||||
### Configuring the Crate Sources
|
||||
|
||||
The sources to check are saved in a `toml` file. There are three types of
|
||||
|
|
|
@ -1,131 +1,79 @@
|
|||
use clap::{Arg, ArgAction, ArgMatches, Command};
|
||||
use std::env;
|
||||
use std::path::PathBuf;
|
||||
use clap::Parser;
|
||||
use std::{num::NonZeroUsize, path::PathBuf};
|
||||
|
||||
fn get_clap_config() -> ArgMatches {
|
||||
Command::new("lintcheck")
|
||||
.about("run clippy on a set of crates and check output")
|
||||
.args([
|
||||
Arg::new("only")
|
||||
.action(ArgAction::Set)
|
||||
.value_name("CRATE")
|
||||
.long("only")
|
||||
.help("Only process a single crate of the list"),
|
||||
Arg::new("crates-toml")
|
||||
.action(ArgAction::Set)
|
||||
.value_name("CRATES-SOURCES-TOML-PATH")
|
||||
.long("crates-toml")
|
||||
.help("Set the path for a crates.toml where lintcheck should read the sources from"),
|
||||
Arg::new("threads")
|
||||
.action(ArgAction::Set)
|
||||
.value_name("N")
|
||||
.value_parser(clap::value_parser!(usize))
|
||||
.short('j')
|
||||
.long("jobs")
|
||||
.help("Number of threads to use, 0 automatic choice"),
|
||||
Arg::new("fix")
|
||||
.long("fix")
|
||||
.help("Runs cargo clippy --fix and checks if all suggestions apply"),
|
||||
Arg::new("filter")
|
||||
.long("filter")
|
||||
.action(ArgAction::Append)
|
||||
.value_name("clippy_lint_name")
|
||||
.help("Apply a filter to only collect specified lints, this also overrides `allow` attributes"),
|
||||
Arg::new("markdown")
|
||||
.long("markdown")
|
||||
.help("Change the reports table to use markdown links"),
|
||||
Arg::new("recursive")
|
||||
.long("recursive")
|
||||
.help("Run clippy on the dependencies of crates specified in crates-toml")
|
||||
.conflicts_with("threads")
|
||||
.conflicts_with("fix"),
|
||||
])
|
||||
.get_matches()
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Clone, Debug, Parser)]
|
||||
pub(crate) struct LintcheckConfig {
|
||||
/// max number of jobs to spawn (default 1)
|
||||
/// Number of threads to use (default: all unless --fix or --recursive)
|
||||
#[clap(
|
||||
long = "jobs",
|
||||
short = 'j',
|
||||
value_name = "N",
|
||||
default_value_t = 0,
|
||||
hide_default_value = true
|
||||
)]
|
||||
pub max_jobs: usize,
|
||||
/// we read the sources to check from here
|
||||
/// Set the path for a crates.toml where lintcheck should read the sources from
|
||||
#[clap(
|
||||
long = "crates-toml",
|
||||
value_name = "CRATES-SOURCES-TOML-PATH",
|
||||
default_value = "lintcheck/lintcheck_crates.toml",
|
||||
hide_default_value = true,
|
||||
env = "LINTCHECK_TOML",
|
||||
hide_env = true
|
||||
)]
|
||||
pub sources_toml_path: PathBuf,
|
||||
/// we save the clippy lint results here
|
||||
pub lintcheck_results_path: PathBuf,
|
||||
/// Check only a specified package
|
||||
/// File to save the clippy lint results here
|
||||
#[clap(skip = "")]
|
||||
pub lintcheck_results_path: PathBuf, // Overridden in new()
|
||||
/// Only process a single crate on the list
|
||||
#[clap(long, value_name = "CRATE")]
|
||||
pub only: Option<String>,
|
||||
/// whether to just run --fix and not collect all the warnings
|
||||
/// Runs cargo clippy --fix and checks if all suggestions apply
|
||||
#[clap(long, conflicts_with("max_jobs"))]
|
||||
pub fix: bool,
|
||||
/// A list of lints that this lintcheck run should focus on
|
||||
/// Apply a filter to only collect specified lints, this also overrides `allow` attributes
|
||||
#[clap(long = "filter", value_name = "clippy_lint_name", use_value_delimiter = true)]
|
||||
pub lint_filter: Vec<String>,
|
||||
/// Indicate if the output should support markdown syntax
|
||||
/// Change the reports table to use markdown links
|
||||
#[clap(long)]
|
||||
pub markdown: bool,
|
||||
/// Run clippy on the dependencies of crates
|
||||
/// Run clippy on the dependencies of crates specified in crates-toml
|
||||
#[clap(long, conflicts_with("max_jobs"))]
|
||||
pub recursive: bool,
|
||||
}
|
||||
|
||||
impl LintcheckConfig {
|
||||
pub fn new() -> Self {
|
||||
let clap_config = get_clap_config();
|
||||
|
||||
// first, check if we got anything passed via the LINTCHECK_TOML env var,
|
||||
// if not, ask clap if we got any value for --crates-toml <foo>
|
||||
// if not, use the default "lintcheck/lintcheck_crates.toml"
|
||||
let sources_toml = env::var("LINTCHECK_TOML").unwrap_or_else(|_| {
|
||||
clap_config
|
||||
.get_one::<String>("crates-toml")
|
||||
.map_or("lintcheck/lintcheck_crates.toml", |s| &**s)
|
||||
.into()
|
||||
});
|
||||
|
||||
let markdown = clap_config.contains_id("markdown");
|
||||
let sources_toml_path = PathBuf::from(sources_toml);
|
||||
let mut config = LintcheckConfig::parse();
|
||||
|
||||
// for the path where we save the lint results, get the filename without extension (so for
|
||||
// wasd.toml, use "wasd"...)
|
||||
let filename: PathBuf = sources_toml_path.file_stem().unwrap().into();
|
||||
let lintcheck_results_path = PathBuf::from(format!(
|
||||
let filename: PathBuf = config.sources_toml_path.file_stem().unwrap().into();
|
||||
config.lintcheck_results_path = PathBuf::from(format!(
|
||||
"lintcheck-logs/{}_logs.{}",
|
||||
filename.display(),
|
||||
if markdown { "md" } else { "txt" }
|
||||
if config.markdown { "md" } else { "txt" }
|
||||
));
|
||||
|
||||
// look at the --threads arg, if 0 is passed, ask rayon rayon how many threads it would spawn and
|
||||
// use half of that for the physical core count
|
||||
// by default use a single thread
|
||||
let max_jobs = match clap_config.get_one::<usize>("threads") {
|
||||
Some(&0) => {
|
||||
// automatic choice
|
||||
// Rayon seems to return thread count so half that for core count
|
||||
rayon::current_num_threads() / 2
|
||||
},
|
||||
Some(&threads) => threads,
|
||||
// no -j passed, use a single thread
|
||||
None => 1,
|
||||
// look at the --threads arg, if 0 is passed, use the threads count
|
||||
if config.max_jobs == 0 {
|
||||
config.max_jobs = if config.fix || config.recursive {
|
||||
1
|
||||
} else {
|
||||
std::thread::available_parallelism().map_or(1, NonZeroUsize::get)
|
||||
};
|
||||
};
|
||||
|
||||
let lint_filter: Vec<String> = clap_config
|
||||
.get_many::<String>("filter")
|
||||
.map(|iter| {
|
||||
iter.map(|lint_name| {
|
||||
let mut filter = lint_name.replace('_', "-");
|
||||
if !filter.starts_with("clippy::") {
|
||||
filter.insert_str(0, "clippy::");
|
||||
}
|
||||
filter
|
||||
})
|
||||
.collect()
|
||||
})
|
||||
.unwrap_or_default();
|
||||
|
||||
LintcheckConfig {
|
||||
max_jobs,
|
||||
sources_toml_path,
|
||||
lintcheck_results_path,
|
||||
only: clap_config.get_one::<String>("only").map(String::from),
|
||||
fix: clap_config.contains_id("fix"),
|
||||
lint_filter,
|
||||
markdown,
|
||||
recursive: clap_config.contains_id("recursive"),
|
||||
for lint_name in &mut config.lint_filter {
|
||||
*lint_name = format!(
|
||||
"clippy::{}",
|
||||
lint_name
|
||||
.strip_prefix("clippy::")
|
||||
.unwrap_or(lint_name)
|
||||
.replace('_', "-")
|
||||
);
|
||||
}
|
||||
|
||||
config
|
||||
}
|
||||
}
|
||||
|
|
65
lintcheck/src/popular-crates.rs
Normal file
65
lintcheck/src/popular-crates.rs
Normal file
|
@ -0,0 +1,65 @@
|
|||
#![deny(clippy::pedantic)]
|
||||
|
||||
use clap::Parser;
|
||||
use crates_io_api::{CratesQueryBuilder, Sort, SyncClient};
|
||||
use indicatif::ProgressBar;
|
||||
use std::collections::HashSet;
|
||||
use std::fs::File;
|
||||
use std::io::{BufWriter, Write};
|
||||
use std::path::PathBuf;
|
||||
use std::time::Duration;
|
||||
|
||||
#[derive(Parser)]
|
||||
struct Opts {
|
||||
/// Output TOML file name
|
||||
output: PathBuf,
|
||||
/// Number of crate names to download
|
||||
#[clap(short, long, default_value_t = 100)]
|
||||
number: usize,
|
||||
/// Do not output progress
|
||||
#[clap(short, long)]
|
||||
quiet: bool,
|
||||
}
|
||||
|
||||
fn main() -> anyhow::Result<()> {
|
||||
let opts = Opts::parse();
|
||||
let mut output = BufWriter::new(File::create(opts.output)?);
|
||||
output.write_all(b"[crates]\n")?;
|
||||
let client = SyncClient::new(
|
||||
"clippy/lintcheck (github.com/rust-lang/rust-clippy/)",
|
||||
Duration::from_secs(1),
|
||||
)?;
|
||||
let mut seen_crates = HashSet::new();
|
||||
let pb = if opts.quiet {
|
||||
None
|
||||
} else {
|
||||
Some(ProgressBar::new(opts.number as u64))
|
||||
};
|
||||
let mut query = CratesQueryBuilder::new()
|
||||
.sort(Sort::RecentDownloads)
|
||||
.page_size(100)
|
||||
.build();
|
||||
while seen_crates.len() < opts.number {
|
||||
let retrieved = client.crates(query.clone())?.crates;
|
||||
if retrieved.is_empty() {
|
||||
eprintln!("No more than {} crates available from API", seen_crates.len());
|
||||
break;
|
||||
}
|
||||
for c in retrieved {
|
||||
if seen_crates.insert(c.name.clone()) {
|
||||
output.write_all(
|
||||
format!(
|
||||
"{} = {{ name = '{}', versions = ['{}'] }}\n",
|
||||
c.name, c.name, c.max_version
|
||||
)
|
||||
.as_bytes(),
|
||||
)?;
|
||||
if let Some(pb) = &pb {
|
||||
pb.inc(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
query.set_page(query.page() + 1);
|
||||
}
|
||||
Ok(())
|
||||
}
|
|
@ -1,3 +1,3 @@
|
|||
[toolchain]
|
||||
channel = "nightly-2023-02-25"
|
||||
channel = "nightly-2023-03-10"
|
||||
components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
|
||||
|
|
|
@ -176,7 +176,7 @@ Common options:
|
|||
--rustc Pass all args to rustc
|
||||
-V, --version Print version info and exit
|
||||
|
||||
Other options are the same as `cargo check`.
|
||||
For the other options see `cargo check --help`.
|
||||
|
||||
To allow or deny a lint from the command line you can use `cargo clippy --`
|
||||
with:
|
||||
|
|
|
@ -18,7 +18,7 @@ Common options:
|
|||
-V, --version Print version info and exit
|
||||
--explain LINT Print the documentation for a given lint
|
||||
|
||||
Other options are the same as `cargo check`.
|
||||
For the other options see `cargo check --help`.
|
||||
|
||||
To allow or deny a lint from the command line you can use `cargo clippy --`
|
||||
with:
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#![cfg_attr(feature = "deny-warnings", deny(warnings))]
|
||||
#![warn(rust_2018_idioms, unused_lifetimes)]
|
||||
|
||||
use itertools::Itertools;
|
||||
use std::path::PathBuf;
|
||||
use std::process::Command;
|
||||
use test_utils::IS_RUSTC_TEST_SUITE;
|
||||
|
@ -19,8 +20,10 @@ fn dogfood_clippy() {
|
|||
return;
|
||||
}
|
||||
|
||||
let mut failed_packages = Vec::new();
|
||||
|
||||
// "" is the root package
|
||||
for package in &[
|
||||
for package in [
|
||||
"",
|
||||
"clippy_dev",
|
||||
"clippy_lints",
|
||||
|
@ -28,8 +31,16 @@ fn dogfood_clippy() {
|
|||
"lintcheck",
|
||||
"rustc_tools_util",
|
||||
] {
|
||||
run_clippy_for_package(package, &["-D", "clippy::all", "-D", "clippy::pedantic"]);
|
||||
if !run_clippy_for_package(package, &["-D", "clippy::all", "-D", "clippy::pedantic"]) {
|
||||
failed_packages.push(if package.is_empty() { "root" } else { package });
|
||||
}
|
||||
}
|
||||
|
||||
assert!(
|
||||
!failed_packages.is_empty(),
|
||||
"Dogfood failed for packages `{}`",
|
||||
failed_packages.iter().format(", "),
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -71,7 +82,7 @@ fn run_metadata_collection_lint() {
|
|||
run_clippy_for_package("clippy_lints", &["-A", "unfulfilled_lint_expectations"]);
|
||||
}
|
||||
|
||||
fn run_clippy_for_package(project: &str, args: &[&str]) {
|
||||
fn run_clippy_for_package(project: &str, args: &[&str]) -> bool {
|
||||
let root_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||
|
||||
let mut command = Command::new(&*test_utils::CARGO_CLIPPY_PATH);
|
||||
|
@ -107,5 +118,5 @@ fn run_clippy_for_package(project: &str, args: &[&str]) {
|
|||
println!("stdout: {}", String::from_utf8_lossy(&output.stdout));
|
||||
println!("stderr: {}", String::from_utf8_lossy(&output.stderr));
|
||||
|
||||
assert!(output.status.success());
|
||||
output.status.success()
|
||||
}
|
||||
|
|
|
@ -45,24 +45,32 @@ impl_arith!(
|
|||
Div, Custom, Custom, div;
|
||||
Mul, Custom, Custom, mul;
|
||||
Rem, Custom, Custom, rem;
|
||||
Shl, Custom, Custom, shl;
|
||||
Shr, Custom, Custom, shr;
|
||||
Sub, Custom, Custom, sub;
|
||||
|
||||
Add, Custom, &Custom, add;
|
||||
Div, Custom, &Custom, div;
|
||||
Mul, Custom, &Custom, mul;
|
||||
Rem, Custom, &Custom, rem;
|
||||
Shl, Custom, &Custom, shl;
|
||||
Shr, Custom, &Custom, shr;
|
||||
Sub, Custom, &Custom, sub;
|
||||
|
||||
Add, &Custom, Custom, add;
|
||||
Div, &Custom, Custom, div;
|
||||
Mul, &Custom, Custom, mul;
|
||||
Rem, &Custom, Custom, rem;
|
||||
Shl, &Custom, Custom, shl;
|
||||
Shr, &Custom, Custom, shr;
|
||||
Sub, &Custom, Custom, sub;
|
||||
|
||||
Add, &Custom, &Custom, add;
|
||||
Div, &Custom, &Custom, div;
|
||||
Mul, &Custom, &Custom, mul;
|
||||
Rem, &Custom, &Custom, rem;
|
||||
Shl, &Custom, &Custom, shl;
|
||||
Shr, &Custom, &Custom, shr;
|
||||
Sub, &Custom, &Custom, sub;
|
||||
);
|
||||
|
||||
|
@ -71,24 +79,32 @@ impl_assign_arith!(
|
|||
DivAssign, Custom, Custom, div_assign;
|
||||
MulAssign, Custom, Custom, mul_assign;
|
||||
RemAssign, Custom, Custom, rem_assign;
|
||||
ShlAssign, Custom, Custom, shl_assign;
|
||||
ShrAssign, Custom, Custom, shr_assign;
|
||||
SubAssign, Custom, Custom, sub_assign;
|
||||
|
||||
AddAssign, Custom, &Custom, add_assign;
|
||||
DivAssign, Custom, &Custom, div_assign;
|
||||
MulAssign, Custom, &Custom, mul_assign;
|
||||
RemAssign, Custom, &Custom, rem_assign;
|
||||
ShlAssign, Custom, &Custom, shl_assign;
|
||||
ShrAssign, Custom, &Custom, shr_assign;
|
||||
SubAssign, Custom, &Custom, sub_assign;
|
||||
|
||||
AddAssign, &Custom, Custom, add_assign;
|
||||
DivAssign, &Custom, Custom, div_assign;
|
||||
MulAssign, &Custom, Custom, mul_assign;
|
||||
RemAssign, &Custom, Custom, rem_assign;
|
||||
ShlAssign, &Custom, Custom, shl_assign;
|
||||
ShrAssign, &Custom, Custom, shr_assign;
|
||||
SubAssign, &Custom, Custom, sub_assign;
|
||||
|
||||
AddAssign, &Custom, &Custom, add_assign;
|
||||
DivAssign, &Custom, &Custom, div_assign;
|
||||
MulAssign, &Custom, &Custom, mul_assign;
|
||||
RemAssign, &Custom, &Custom, rem_assign;
|
||||
ShlAssign, &Custom, &Custom, shl_assign;
|
||||
ShrAssign, &Custom, &Custom, shr_assign;
|
||||
SubAssign, &Custom, &Custom, sub_assign;
|
||||
);
|
||||
|
||||
|
@ -297,6 +313,10 @@ pub fn unknown_ops_or_runtime_ops_that_can_overflow() {
|
|||
_custom %= &Custom;
|
||||
_custom *= Custom;
|
||||
_custom *= &Custom;
|
||||
_custom >>= Custom;
|
||||
_custom >>= &Custom;
|
||||
_custom <<= Custom;
|
||||
_custom <<= &Custom;
|
||||
_custom += -Custom;
|
||||
_custom += &-Custom;
|
||||
_custom -= -Custom;
|
||||
|
@ -307,6 +327,10 @@ pub fn unknown_ops_or_runtime_ops_that_can_overflow() {
|
|||
_custom %= &-Custom;
|
||||
_custom *= -Custom;
|
||||
_custom *= &-Custom;
|
||||
_custom >>= -Custom;
|
||||
_custom >>= &-Custom;
|
||||
_custom <<= -Custom;
|
||||
_custom <<= &-Custom;
|
||||
|
||||
// Binary
|
||||
_n = _n + 1;
|
||||
|
@ -347,6 +371,10 @@ pub fn unknown_ops_or_runtime_ops_that_can_overflow() {
|
|||
_custom = Custom + &Custom;
|
||||
_custom = &Custom + Custom;
|
||||
_custom = &Custom + &Custom;
|
||||
_custom = _custom >> _custom;
|
||||
_custom = _custom >> &_custom;
|
||||
_custom = Custom << _custom;
|
||||
_custom = &Custom << _custom;
|
||||
|
||||
// Unary
|
||||
_n = -_n;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:270:5
|
||||
--> $DIR/arithmetic_side_effects.rs:286:5
|
||||
|
|
||||
LL | _n += 1;
|
||||
| ^^^^^^^
|
||||
|
@ -7,592 +7,640 @@ LL | _n += 1;
|
|||
= note: `-D clippy::arithmetic-side-effects` implied by `-D warnings`
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:271:5
|
||||
--> $DIR/arithmetic_side_effects.rs:287:5
|
||||
|
|
||||
LL | _n += &1;
|
||||
| ^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:272:5
|
||||
--> $DIR/arithmetic_side_effects.rs:288:5
|
||||
|
|
||||
LL | _n -= 1;
|
||||
| ^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:273:5
|
||||
--> $DIR/arithmetic_side_effects.rs:289:5
|
||||
|
|
||||
LL | _n -= &1;
|
||||
| ^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:274:5
|
||||
--> $DIR/arithmetic_side_effects.rs:290:5
|
||||
|
|
||||
LL | _n /= 0;
|
||||
| ^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:275:5
|
||||
--> $DIR/arithmetic_side_effects.rs:291:5
|
||||
|
|
||||
LL | _n /= &0;
|
||||
| ^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:276:5
|
||||
--> $DIR/arithmetic_side_effects.rs:292:5
|
||||
|
|
||||
LL | _n %= 0;
|
||||
| ^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:277:5
|
||||
--> $DIR/arithmetic_side_effects.rs:293:5
|
||||
|
|
||||
LL | _n %= &0;
|
||||
| ^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:278:5
|
||||
--> $DIR/arithmetic_side_effects.rs:294:5
|
||||
|
|
||||
LL | _n *= 2;
|
||||
| ^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:279:5
|
||||
--> $DIR/arithmetic_side_effects.rs:295:5
|
||||
|
|
||||
LL | _n *= &2;
|
||||
| ^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:280:5
|
||||
--> $DIR/arithmetic_side_effects.rs:296:5
|
||||
|
|
||||
LL | _n += -1;
|
||||
| ^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:281:5
|
||||
--> $DIR/arithmetic_side_effects.rs:297:5
|
||||
|
|
||||
LL | _n += &-1;
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:282:5
|
||||
--> $DIR/arithmetic_side_effects.rs:298:5
|
||||
|
|
||||
LL | _n -= -1;
|
||||
| ^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:283:5
|
||||
--> $DIR/arithmetic_side_effects.rs:299:5
|
||||
|
|
||||
LL | _n -= &-1;
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:284:5
|
||||
--> $DIR/arithmetic_side_effects.rs:300:5
|
||||
|
|
||||
LL | _n /= -0;
|
||||
| ^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:285:5
|
||||
--> $DIR/arithmetic_side_effects.rs:301:5
|
||||
|
|
||||
LL | _n /= &-0;
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:286:5
|
||||
--> $DIR/arithmetic_side_effects.rs:302:5
|
||||
|
|
||||
LL | _n %= -0;
|
||||
| ^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:287:5
|
||||
--> $DIR/arithmetic_side_effects.rs:303:5
|
||||
|
|
||||
LL | _n %= &-0;
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:288:5
|
||||
--> $DIR/arithmetic_side_effects.rs:304:5
|
||||
|
|
||||
LL | _n *= -2;
|
||||
| ^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:289:5
|
||||
--> $DIR/arithmetic_side_effects.rs:305:5
|
||||
|
|
||||
LL | _n *= &-2;
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:290:5
|
||||
--> $DIR/arithmetic_side_effects.rs:306:5
|
||||
|
|
||||
LL | _custom += Custom;
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:291:5
|
||||
--> $DIR/arithmetic_side_effects.rs:307:5
|
||||
|
|
||||
LL | _custom += &Custom;
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:292:5
|
||||
--> $DIR/arithmetic_side_effects.rs:308:5
|
||||
|
|
||||
LL | _custom -= Custom;
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:293:5
|
||||
--> $DIR/arithmetic_side_effects.rs:309:5
|
||||
|
|
||||
LL | _custom -= &Custom;
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:294:5
|
||||
--> $DIR/arithmetic_side_effects.rs:310:5
|
||||
|
|
||||
LL | _custom /= Custom;
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:295:5
|
||||
--> $DIR/arithmetic_side_effects.rs:311:5
|
||||
|
|
||||
LL | _custom /= &Custom;
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:296:5
|
||||
--> $DIR/arithmetic_side_effects.rs:312:5
|
||||
|
|
||||
LL | _custom %= Custom;
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:297:5
|
||||
--> $DIR/arithmetic_side_effects.rs:313:5
|
||||
|
|
||||
LL | _custom %= &Custom;
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:298:5
|
||||
--> $DIR/arithmetic_side_effects.rs:314:5
|
||||
|
|
||||
LL | _custom *= Custom;
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:299:5
|
||||
--> $DIR/arithmetic_side_effects.rs:315:5
|
||||
|
|
||||
LL | _custom *= &Custom;
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:300:5
|
||||
--> $DIR/arithmetic_side_effects.rs:316:5
|
||||
|
|
||||
LL | _custom >>= Custom;
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:317:5
|
||||
|
|
||||
LL | _custom >>= &Custom;
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:318:5
|
||||
|
|
||||
LL | _custom <<= Custom;
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:319:5
|
||||
|
|
||||
LL | _custom <<= &Custom;
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:320:5
|
||||
|
|
||||
LL | _custom += -Custom;
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:301:5
|
||||
--> $DIR/arithmetic_side_effects.rs:321:5
|
||||
|
|
||||
LL | _custom += &-Custom;
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:302:5
|
||||
--> $DIR/arithmetic_side_effects.rs:322:5
|
||||
|
|
||||
LL | _custom -= -Custom;
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:303:5
|
||||
--> $DIR/arithmetic_side_effects.rs:323:5
|
||||
|
|
||||
LL | _custom -= &-Custom;
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:304:5
|
||||
--> $DIR/arithmetic_side_effects.rs:324:5
|
||||
|
|
||||
LL | _custom /= -Custom;
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:305:5
|
||||
--> $DIR/arithmetic_side_effects.rs:325:5
|
||||
|
|
||||
LL | _custom /= &-Custom;
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:306:5
|
||||
--> $DIR/arithmetic_side_effects.rs:326:5
|
||||
|
|
||||
LL | _custom %= -Custom;
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:307:5
|
||||
--> $DIR/arithmetic_side_effects.rs:327:5
|
||||
|
|
||||
LL | _custom %= &-Custom;
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:308:5
|
||||
--> $DIR/arithmetic_side_effects.rs:328:5
|
||||
|
|
||||
LL | _custom *= -Custom;
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:309:5
|
||||
--> $DIR/arithmetic_side_effects.rs:329:5
|
||||
|
|
||||
LL | _custom *= &-Custom;
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:312:10
|
||||
--> $DIR/arithmetic_side_effects.rs:330:5
|
||||
|
|
||||
LL | _custom >>= -Custom;
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:331:5
|
||||
|
|
||||
LL | _custom >>= &-Custom;
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:332:5
|
||||
|
|
||||
LL | _custom <<= -Custom;
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:333:5
|
||||
|
|
||||
LL | _custom <<= &-Custom;
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:336:10
|
||||
|
|
||||
LL | _n = _n + 1;
|
||||
| ^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:313:10
|
||||
--> $DIR/arithmetic_side_effects.rs:337:10
|
||||
|
|
||||
LL | _n = _n + &1;
|
||||
| ^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:314:10
|
||||
--> $DIR/arithmetic_side_effects.rs:338:10
|
||||
|
|
||||
LL | _n = 1 + _n;
|
||||
| ^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:315:10
|
||||
--> $DIR/arithmetic_side_effects.rs:339:10
|
||||
|
|
||||
LL | _n = &1 + _n;
|
||||
| ^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:316:10
|
||||
--> $DIR/arithmetic_side_effects.rs:340:10
|
||||
|
|
||||
LL | _n = _n - 1;
|
||||
| ^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:317:10
|
||||
--> $DIR/arithmetic_side_effects.rs:341:10
|
||||
|
|
||||
LL | _n = _n - &1;
|
||||
| ^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:318:10
|
||||
--> $DIR/arithmetic_side_effects.rs:342:10
|
||||
|
|
||||
LL | _n = 1 - _n;
|
||||
| ^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:319:10
|
||||
--> $DIR/arithmetic_side_effects.rs:343:10
|
||||
|
|
||||
LL | _n = &1 - _n;
|
||||
| ^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:320:10
|
||||
--> $DIR/arithmetic_side_effects.rs:344:10
|
||||
|
|
||||
LL | _n = _n / 0;
|
||||
| ^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:321:10
|
||||
--> $DIR/arithmetic_side_effects.rs:345:10
|
||||
|
|
||||
LL | _n = _n / &0;
|
||||
| ^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:322:10
|
||||
--> $DIR/arithmetic_side_effects.rs:346:10
|
||||
|
|
||||
LL | _n = _n % 0;
|
||||
| ^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:323:10
|
||||
--> $DIR/arithmetic_side_effects.rs:347:10
|
||||
|
|
||||
LL | _n = _n % &0;
|
||||
| ^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:324:10
|
||||
--> $DIR/arithmetic_side_effects.rs:348:10
|
||||
|
|
||||
LL | _n = _n * 2;
|
||||
| ^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:325:10
|
||||
--> $DIR/arithmetic_side_effects.rs:349:10
|
||||
|
|
||||
LL | _n = _n * &2;
|
||||
| ^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:326:10
|
||||
--> $DIR/arithmetic_side_effects.rs:350:10
|
||||
|
|
||||
LL | _n = 2 * _n;
|
||||
| ^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:327:10
|
||||
--> $DIR/arithmetic_side_effects.rs:351:10
|
||||
|
|
||||
LL | _n = &2 * _n;
|
||||
| ^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:328:10
|
||||
--> $DIR/arithmetic_side_effects.rs:352:10
|
||||
|
|
||||
LL | _n = 23 + &85;
|
||||
| ^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:329:10
|
||||
--> $DIR/arithmetic_side_effects.rs:353:10
|
||||
|
|
||||
LL | _n = &23 + 85;
|
||||
| ^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:330:10
|
||||
--> $DIR/arithmetic_side_effects.rs:354:10
|
||||
|
|
||||
LL | _n = &23 + &85;
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:331:15
|
||||
--> $DIR/arithmetic_side_effects.rs:355:15
|
||||
|
|
||||
LL | _custom = _custom + _custom;
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:332:15
|
||||
--> $DIR/arithmetic_side_effects.rs:356:15
|
||||
|
|
||||
LL | _custom = _custom + &_custom;
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:333:15
|
||||
--> $DIR/arithmetic_side_effects.rs:357:15
|
||||
|
|
||||
LL | _custom = Custom + _custom;
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:334:15
|
||||
--> $DIR/arithmetic_side_effects.rs:358:15
|
||||
|
|
||||
LL | _custom = &Custom + _custom;
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:335:15
|
||||
--> $DIR/arithmetic_side_effects.rs:359:15
|
||||
|
|
||||
LL | _custom = _custom - Custom;
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:336:15
|
||||
--> $DIR/arithmetic_side_effects.rs:360:15
|
||||
|
|
||||
LL | _custom = _custom - &Custom;
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:337:15
|
||||
--> $DIR/arithmetic_side_effects.rs:361:15
|
||||
|
|
||||
LL | _custom = Custom - _custom;
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:338:15
|
||||
--> $DIR/arithmetic_side_effects.rs:362:15
|
||||
|
|
||||
LL | _custom = &Custom - _custom;
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:339:15
|
||||
--> $DIR/arithmetic_side_effects.rs:363:15
|
||||
|
|
||||
LL | _custom = _custom / Custom;
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:340:15
|
||||
--> $DIR/arithmetic_side_effects.rs:364:15
|
||||
|
|
||||
LL | _custom = _custom / &Custom;
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:341:15
|
||||
--> $DIR/arithmetic_side_effects.rs:365:15
|
||||
|
|
||||
LL | _custom = _custom % Custom;
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:342:15
|
||||
--> $DIR/arithmetic_side_effects.rs:366:15
|
||||
|
|
||||
LL | _custom = _custom % &Custom;
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:343:15
|
||||
--> $DIR/arithmetic_side_effects.rs:367:15
|
||||
|
|
||||
LL | _custom = _custom * Custom;
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:344:15
|
||||
--> $DIR/arithmetic_side_effects.rs:368:15
|
||||
|
|
||||
LL | _custom = _custom * &Custom;
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:345:15
|
||||
--> $DIR/arithmetic_side_effects.rs:369:15
|
||||
|
|
||||
LL | _custom = Custom * _custom;
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:346:15
|
||||
--> $DIR/arithmetic_side_effects.rs:370:15
|
||||
|
|
||||
LL | _custom = &Custom * _custom;
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:347:15
|
||||
--> $DIR/arithmetic_side_effects.rs:371:15
|
||||
|
|
||||
LL | _custom = Custom + &Custom;
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:348:15
|
||||
--> $DIR/arithmetic_side_effects.rs:372:15
|
||||
|
|
||||
LL | _custom = &Custom + Custom;
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:349:15
|
||||
--> $DIR/arithmetic_side_effects.rs:373:15
|
||||
|
|
||||
LL | _custom = &Custom + &Custom;
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:352:10
|
||||
--> $DIR/arithmetic_side_effects.rs:374:15
|
||||
|
|
||||
LL | _custom = _custom >> _custom;
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:375:15
|
||||
|
|
||||
LL | _custom = _custom >> &_custom;
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:376:15
|
||||
|
|
||||
LL | _custom = Custom << _custom;
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:377:15
|
||||
|
|
||||
LL | _custom = &Custom << _custom;
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:380:10
|
||||
|
|
||||
LL | _n = -_n;
|
||||
| ^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:353:10
|
||||
--> $DIR/arithmetic_side_effects.rs:381:10
|
||||
|
|
||||
LL | _n = -&_n;
|
||||
| ^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:354:15
|
||||
--> $DIR/arithmetic_side_effects.rs:382:15
|
||||
|
|
||||
LL | _custom = -_custom;
|
||||
| ^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:355:15
|
||||
--> $DIR/arithmetic_side_effects.rs:383:15
|
||||
|
|
||||
LL | _custom = -&_custom;
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:364:5
|
||||
--> $DIR/arithmetic_side_effects.rs:392:5
|
||||
|
|
||||
LL | 1 + i;
|
||||
| ^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:365:5
|
||||
--> $DIR/arithmetic_side_effects.rs:393:5
|
||||
|
|
||||
LL | i * 2;
|
||||
| ^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:367:5
|
||||
--> $DIR/arithmetic_side_effects.rs:395:5
|
||||
|
|
||||
LL | i - 2 + 2 - i;
|
||||
| ^^^^^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:368:5
|
||||
--> $DIR/arithmetic_side_effects.rs:396:5
|
||||
|
|
||||
LL | -i;
|
||||
| ^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:369:5
|
||||
|
|
||||
LL | i >> 1;
|
||||
| ^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:370:5
|
||||
|
|
||||
LL | i << 1;
|
||||
| ^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:379:5
|
||||
--> $DIR/arithmetic_side_effects.rs:407:5
|
||||
|
|
||||
LL | i += 1;
|
||||
| ^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:380:5
|
||||
--> $DIR/arithmetic_side_effects.rs:408:5
|
||||
|
|
||||
LL | i -= 1;
|
||||
| ^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:381:5
|
||||
--> $DIR/arithmetic_side_effects.rs:409:5
|
||||
|
|
||||
LL | i *= 2;
|
||||
| ^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:383:5
|
||||
--> $DIR/arithmetic_side_effects.rs:411:5
|
||||
|
|
||||
LL | i /= 0;
|
||||
| ^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:385:5
|
||||
--> $DIR/arithmetic_side_effects.rs:413:5
|
||||
|
|
||||
LL | i /= var1;
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:386:5
|
||||
--> $DIR/arithmetic_side_effects.rs:414:5
|
||||
|
|
||||
LL | i /= var2;
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:388:5
|
||||
--> $DIR/arithmetic_side_effects.rs:416:5
|
||||
|
|
||||
LL | i %= 0;
|
||||
| ^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:390:5
|
||||
--> $DIR/arithmetic_side_effects.rs:418:5
|
||||
|
|
||||
LL | i %= var1;
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:391:5
|
||||
--> $DIR/arithmetic_side_effects.rs:419:5
|
||||
|
|
||||
LL | i %= var2;
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:392:5
|
||||
|
|
||||
LL | i <<= 3;
|
||||
| ^^^^^^^
|
||||
|
||||
error: arithmetic operation that can potentially result in unexpected side-effects
|
||||
--> $DIR/arithmetic_side_effects.rs:393:5
|
||||
|
|
||||
LL | i >>= 2;
|
||||
| ^^^^^^^
|
||||
|
||||
error: aborting due to 99 previous errors
|
||||
error: aborting due to 107 previous errors
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#![feature(lint_reasons)]
|
||||
#![feature(async_closure)]
|
||||
#![warn(clippy::async_yields_async)]
|
||||
#![allow(clippy::redundant_async_block)]
|
||||
|
||||
use core::future::Future;
|
||||
use core::pin::Pin;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#![feature(lint_reasons)]
|
||||
#![feature(async_closure)]
|
||||
#![warn(clippy::async_yields_async)]
|
||||
#![allow(clippy::redundant_async_block)]
|
||||
|
||||
use core::future::Future;
|
||||
use core::pin::Pin;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
error: an async construct yields a type which is itself awaitable
|
||||
--> $DIR/async_yields_async.rs:39:9
|
||||
--> $DIR/async_yields_async.rs:40:9
|
||||
|
|
||||
LL | let _h = async {
|
||||
| _____________________-
|
||||
|
@ -19,7 +19,7 @@ LL + }.await
|
|||
|
|
||||
|
||||
error: an async construct yields a type which is itself awaitable
|
||||
--> $DIR/async_yields_async.rs:44:9
|
||||
--> $DIR/async_yields_async.rs:45:9
|
||||
|
|
||||
LL | let _i = async {
|
||||
| ____________________-
|
||||
|
@ -32,7 +32,7 @@ LL | | };
|
|||
| |_____- outer async construct
|
||||
|
||||
error: an async construct yields a type which is itself awaitable
|
||||
--> $DIR/async_yields_async.rs:50:9
|
||||
--> $DIR/async_yields_async.rs:51:9
|
||||
|
|
||||
LL | let _j = async || {
|
||||
| ________________________-
|
||||
|
@ -51,7 +51,7 @@ LL + }.await
|
|||
|
|
||||
|
||||
error: an async construct yields a type which is itself awaitable
|
||||
--> $DIR/async_yields_async.rs:55:9
|
||||
--> $DIR/async_yields_async.rs:56:9
|
||||
|
|
||||
LL | let _k = async || {
|
||||
| _______________________-
|
||||
|
@ -64,7 +64,7 @@ LL | | };
|
|||
| |_____- outer async construct
|
||||
|
||||
error: an async construct yields a type which is itself awaitable
|
||||
--> $DIR/async_yields_async.rs:57:23
|
||||
--> $DIR/async_yields_async.rs:58:23
|
||||
|
|
||||
LL | let _l = async || CustomFutureType;
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
@ -74,7 +74,7 @@ LL | let _l = async || CustomFutureType;
|
|||
| help: consider awaiting this value: `CustomFutureType.await`
|
||||
|
||||
error: an async construct yields a type which is itself awaitable
|
||||
--> $DIR/async_yields_async.rs:63:9
|
||||
--> $DIR/async_yields_async.rs:64:9
|
||||
|
|
||||
LL | let _m = async || {
|
||||
| _______________________-
|
||||
|
|
165
tests/ui/collection_is_never_read.rs
Normal file
165
tests/ui/collection_is_never_read.rs
Normal file
|
@ -0,0 +1,165 @@
|
|||
#![allow(unused)]
|
||||
#![warn(clippy::collection_is_never_read)]
|
||||
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
fn main() {}
|
||||
|
||||
fn not_a_collection() {
|
||||
// TODO: Expand `collection_is_never_read` beyond collections?
|
||||
let mut x = 10; // Ok
|
||||
x += 1;
|
||||
}
|
||||
|
||||
fn no_access_at_all() {
|
||||
// Other lints should catch this.
|
||||
let x = vec![1, 2, 3]; // Ok
|
||||
}
|
||||
|
||||
fn write_without_read() {
|
||||
// The main use case for `collection_is_never_read`.
|
||||
let mut x = HashMap::new(); // WARNING
|
||||
x.insert(1, 2);
|
||||
}
|
||||
|
||||
fn read_without_write() {
|
||||
let mut x = vec![1, 2, 3]; // Ok
|
||||
let _ = x.len();
|
||||
}
|
||||
|
||||
fn write_and_read() {
|
||||
let mut x = vec![1, 2, 3]; // Ok
|
||||
x.push(4);
|
||||
let _ = x.len();
|
||||
}
|
||||
|
||||
fn write_after_read() {
|
||||
// TODO: Warn here, but this requires more extensive data flow analysis.
|
||||
let mut x = vec![1, 2, 3]; // Ok
|
||||
let _ = x.len();
|
||||
x.push(4); // Pointless
|
||||
}
|
||||
|
||||
fn write_before_reassign() {
|
||||
// TODO: Warn here, but this requires more extensive data flow analysis.
|
||||
let mut x = HashMap::new(); // Ok
|
||||
x.insert(1, 2); // Pointless
|
||||
x = HashMap::new();
|
||||
let _ = x.len();
|
||||
}
|
||||
|
||||
fn read_in_closure() {
|
||||
let mut x = HashMap::new(); // Ok
|
||||
x.insert(1, 2);
|
||||
let _ = || {
|
||||
let _ = x.len();
|
||||
};
|
||||
}
|
||||
|
||||
fn write_in_closure() {
|
||||
let mut x = vec![1, 2, 3]; // WARNING
|
||||
let _ = || {
|
||||
x.push(4);
|
||||
};
|
||||
}
|
||||
|
||||
fn read_in_format() {
|
||||
let mut x = HashMap::new(); // Ok
|
||||
x.insert(1, 2);
|
||||
format!("{x:?}");
|
||||
}
|
||||
|
||||
fn shadowing_1() {
|
||||
let x = HashMap::<usize, usize>::new(); // Ok
|
||||
let _ = x.len();
|
||||
let mut x = HashMap::new(); // WARNING
|
||||
x.insert(1, 2);
|
||||
}
|
||||
|
||||
fn shadowing_2() {
|
||||
let mut x = HashMap::new(); // WARNING
|
||||
x.insert(1, 2);
|
||||
let x = HashMap::<usize, usize>::new(); // Ok
|
||||
let _ = x.len();
|
||||
}
|
||||
|
||||
#[allow(clippy::let_unit_value)]
|
||||
fn fake_read() {
|
||||
let mut x = vec![1, 2, 3]; // Ok
|
||||
x.reverse();
|
||||
// `collection_is_never_read` gets fooled, but other lints should catch this.
|
||||
let _: () = x.clear();
|
||||
}
|
||||
|
||||
fn assignment() {
|
||||
let mut x = vec![1, 2, 3]; // WARNING
|
||||
let y = vec![4, 5, 6]; // Ok
|
||||
x = y;
|
||||
}
|
||||
|
||||
#[allow(clippy::self_assignment)]
|
||||
fn self_assignment() {
|
||||
let mut x = vec![1, 2, 3]; // WARNING
|
||||
x = x;
|
||||
}
|
||||
|
||||
fn method_argument_but_not_target() {
|
||||
struct MyStruct;
|
||||
impl MyStruct {
|
||||
fn my_method(&self, _argument: &[usize]) {}
|
||||
}
|
||||
let my_struct = MyStruct;
|
||||
|
||||
let mut x = vec![1, 2, 3]; // Ok
|
||||
x.reverse();
|
||||
my_struct.my_method(&x);
|
||||
}
|
||||
|
||||
fn insert_is_not_a_read() {
|
||||
let mut x = HashSet::new(); // WARNING
|
||||
x.insert(5);
|
||||
}
|
||||
|
||||
fn insert_is_a_read() {
|
||||
let mut x = HashSet::new(); // Ok
|
||||
if x.insert(5) {
|
||||
println!("5 was inserted");
|
||||
}
|
||||
}
|
||||
|
||||
fn not_read_if_return_value_not_used() {
|
||||
// `is_empty` does not modify the set, so it's a query. But since the return value is not used, the
|
||||
// lint does not consider it a read here.
|
||||
let x = vec![1, 2, 3]; // WARNING
|
||||
x.is_empty();
|
||||
}
|
||||
|
||||
fn extension_traits() {
|
||||
trait VecExt<T> {
|
||||
fn method_with_side_effect(&self);
|
||||
fn method_without_side_effect(&self);
|
||||
}
|
||||
|
||||
impl<T> VecExt<T> for Vec<T> {
|
||||
fn method_with_side_effect(&self) {
|
||||
println!("my length: {}", self.len());
|
||||
}
|
||||
fn method_without_side_effect(&self) {}
|
||||
}
|
||||
|
||||
let x = vec![1, 2, 3]; // Ok
|
||||
x.method_with_side_effect();
|
||||
|
||||
let y = vec![1, 2, 3]; // Ok (false negative)
|
||||
y.method_without_side_effect();
|
||||
}
|
||||
|
||||
fn function_argument() {
|
||||
#[allow(clippy::ptr_arg)]
|
||||
fn foo<T>(v: &Vec<T>) -> usize {
|
||||
v.len()
|
||||
}
|
||||
|
||||
let x = vec![1, 2, 3]; // Ok
|
||||
foo(&x);
|
||||
}
|
52
tests/ui/collection_is_never_read.stderr
Normal file
52
tests/ui/collection_is_never_read.stderr
Normal file
|
@ -0,0 +1,52 @@
|
|||
error: collection is never read
|
||||
--> $DIR/collection_is_never_read.rs:21:5
|
||||
|
|
||||
LL | let mut x = HashMap::new(); // WARNING
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `-D clippy::collection-is-never-read` implied by `-D warnings`
|
||||
|
||||
error: collection is never read
|
||||
--> $DIR/collection_is_never_read.rs:60:5
|
||||
|
|
||||
LL | let mut x = vec![1, 2, 3]; // WARNING
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: collection is never read
|
||||
--> $DIR/collection_is_never_read.rs:75:5
|
||||
|
|
||||
LL | let mut x = HashMap::new(); // WARNING
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: collection is never read
|
||||
--> $DIR/collection_is_never_read.rs:80:5
|
||||
|
|
||||
LL | let mut x = HashMap::new(); // WARNING
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: collection is never read
|
||||
--> $DIR/collection_is_never_read.rs:95:5
|
||||
|
|
||||
LL | let mut x = vec![1, 2, 3]; // WARNING
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: collection is never read
|
||||
--> $DIR/collection_is_never_read.rs:102:5
|
||||
|
|
||||
LL | let mut x = vec![1, 2, 3]; // WARNING
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: collection is never read
|
||||
--> $DIR/collection_is_never_read.rs:119:5
|
||||
|
|
||||
LL | let mut x = HashSet::new(); // WARNING
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: collection is never read
|
||||
--> $DIR/collection_is_never_read.rs:133:5
|
||||
|
|
||||
LL | let x = vec![1, 2, 3]; // WARNING
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 8 previous errors
|
||||
|
9
tests/ui/crashes/ice-10148.rs
Normal file
9
tests/ui/crashes/ice-10148.rs
Normal file
|
@ -0,0 +1,9 @@
|
|||
// aux-build:../../auxiliary/proc_macro_with_span.rs
|
||||
|
||||
extern crate proc_macro_with_span;
|
||||
|
||||
use proc_macro_with_span::with_span;
|
||||
|
||||
fn main() {
|
||||
println!(with_span!(""something ""));
|
||||
}
|
12
tests/ui/crashes/ice-10148.stderr
Normal file
12
tests/ui/crashes/ice-10148.stderr
Normal file
|
@ -0,0 +1,12 @@
|
|||
error: empty string literal in `println!`
|
||||
--> $DIR/ice-10148.rs:8:5
|
||||
|
|
||||
LL | println!(with_span!(""something ""));
|
||||
| ^^^^^^^^^^^^^^^^^^^^-----------^^^^^
|
||||
| |
|
||||
| help: remove the empty string
|
||||
|
|
||||
= note: `-D clippy::println-empty-string` implied by `-D warnings`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
//! The ICE is mainly caused by using `hir_ty_to_ty`. See the discussion in the PR for details.
|
||||
|
||||
#![warn(clippy::use_self)]
|
||||
#![allow(dead_code)]
|
||||
#![allow(dead_code, clippy::let_with_type_underscore)]
|
||||
|
||||
struct Foo;
|
||||
|
||||
|
|
17
tests/ui/crashes/ice-rust-107877.rs
Normal file
17
tests/ui/crashes/ice-rust-107877.rs
Normal file
|
@ -0,0 +1,17 @@
|
|||
#![allow(dead_code)]
|
||||
|
||||
struct Foo;
|
||||
|
||||
impl<'a> std::convert::TryFrom<&'a String> for Foo {
|
||||
type Error = std::convert::Infallible;
|
||||
|
||||
fn try_from(_: &'a String) -> Result<Self, Self::Error> {
|
||||
Ok(Foo)
|
||||
}
|
||||
}
|
||||
|
||||
fn find<E>(_: impl std::convert::TryInto<Foo, Error = E>) {}
|
||||
|
||||
fn main() {
|
||||
find(&String::new());
|
||||
}
|
|
@ -9,7 +9,8 @@
|
|||
clippy::unnecessary_operation,
|
||||
clippy::branches_sharing_code,
|
||||
clippy::match_single_binding,
|
||||
clippy::let_unit_value
|
||||
clippy::let_unit_value,
|
||||
clippy::let_with_type_underscore
|
||||
)]
|
||||
|
||||
#[macro_use]
|
||||
|
|
|
@ -9,7 +9,8 @@
|
|||
clippy::unnecessary_operation,
|
||||
clippy::branches_sharing_code,
|
||||
clippy::match_single_binding,
|
||||
clippy::let_unit_value
|
||||
clippy::let_unit_value,
|
||||
clippy::let_with_type_underscore
|
||||
)]
|
||||
|
||||
#[macro_use]
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
error: default numeric fallback might occur
|
||||
--> $DIR/default_numeric_fallback_f64.rs:21:17
|
||||
--> $DIR/default_numeric_fallback_f64.rs:22:17
|
||||
|
|
||||
LL | let x = 0.12;
|
||||
| ^^^^ help: consider adding suffix: `0.12_f64`
|
||||
|
@ -7,139 +7,139 @@ LL | let x = 0.12;
|
|||
= note: `-D clippy::default-numeric-fallback` implied by `-D warnings`
|
||||
|
||||
error: default numeric fallback might occur
|
||||
--> $DIR/default_numeric_fallback_f64.rs:22:18
|
||||
--> $DIR/default_numeric_fallback_f64.rs:23:18
|
||||
|
|
||||
LL | let x = [1., 2., 3.];
|
||||
| ^^ help: consider adding suffix: `1.0_f64`
|
||||
|
||||
error: default numeric fallback might occur
|
||||
--> $DIR/default_numeric_fallback_f64.rs:22:22
|
||||
--> $DIR/default_numeric_fallback_f64.rs:23:22
|
||||
|
|
||||
LL | let x = [1., 2., 3.];
|
||||
| ^^ help: consider adding suffix: `2.0_f64`
|
||||
|
||||
error: default numeric fallback might occur
|
||||
--> $DIR/default_numeric_fallback_f64.rs:22:26
|
||||
--> $DIR/default_numeric_fallback_f64.rs:23:26
|
||||
|
|
||||
LL | let x = [1., 2., 3.];
|
||||
| ^^ help: consider adding suffix: `3.0_f64`
|
||||
|
||||
error: default numeric fallback might occur
|
||||
--> $DIR/default_numeric_fallback_f64.rs:23:28
|
||||
--> $DIR/default_numeric_fallback_f64.rs:24:28
|
||||
|
|
||||
LL | let x = if true { (1., 2.) } else { (3., 4.) };
|
||||
| ^^ help: consider adding suffix: `1.0_f64`
|
||||
|
||||
error: default numeric fallback might occur
|
||||
--> $DIR/default_numeric_fallback_f64.rs:23:32
|
||||
--> $DIR/default_numeric_fallback_f64.rs:24:32
|
||||
|
|
||||
LL | let x = if true { (1., 2.) } else { (3., 4.) };
|
||||
| ^^ help: consider adding suffix: `2.0_f64`
|
||||
|
||||
error: default numeric fallback might occur
|
||||
--> $DIR/default_numeric_fallback_f64.rs:23:46
|
||||
--> $DIR/default_numeric_fallback_f64.rs:24:46
|
||||
|
|
||||
LL | let x = if true { (1., 2.) } else { (3., 4.) };
|
||||
| ^^ help: consider adding suffix: `3.0_f64`
|
||||
|
||||
error: default numeric fallback might occur
|
||||
--> $DIR/default_numeric_fallback_f64.rs:23:50
|
||||
--> $DIR/default_numeric_fallback_f64.rs:24:50
|
||||
|
|
||||
LL | let x = if true { (1., 2.) } else { (3., 4.) };
|
||||
| ^^ help: consider adding suffix: `4.0_f64`
|
||||
|
||||
error: default numeric fallback might occur
|
||||
--> $DIR/default_numeric_fallback_f64.rs:24:23
|
||||
--> $DIR/default_numeric_fallback_f64.rs:25:23
|
||||
|
|
||||
LL | let x = match 1. {
|
||||
| ^^ help: consider adding suffix: `1.0_f64`
|
||||
|
||||
error: default numeric fallback might occur
|
||||
--> $DIR/default_numeric_fallback_f64.rs:25:18
|
||||
--> $DIR/default_numeric_fallback_f64.rs:26:18
|
||||
|
|
||||
LL | _ => 1.,
|
||||
| ^^ help: consider adding suffix: `1.0_f64`
|
||||
|
||||
error: default numeric fallback might occur
|
||||
--> $DIR/default_numeric_fallback_f64.rs:44:21
|
||||
--> $DIR/default_numeric_fallback_f64.rs:45:21
|
||||
|
|
||||
LL | let y = 1.;
|
||||
| ^^ help: consider adding suffix: `1.0_f64`
|
||||
|
||||
error: default numeric fallback might occur
|
||||
--> $DIR/default_numeric_fallback_f64.rs:52:21
|
||||
--> $DIR/default_numeric_fallback_f64.rs:53:21
|
||||
|
|
||||
LL | let y = 1.;
|
||||
| ^^ help: consider adding suffix: `1.0_f64`
|
||||
|
||||
error: default numeric fallback might occur
|
||||
--> $DIR/default_numeric_fallback_f64.rs:58:21
|
||||
--> $DIR/default_numeric_fallback_f64.rs:59:21
|
||||
|
|
||||
LL | let y = 1.;
|
||||
| ^^ help: consider adding suffix: `1.0_f64`
|
||||
|
||||
error: default numeric fallback might occur
|
||||
--> $DIR/default_numeric_fallback_f64.rs:66:21
|
||||
--> $DIR/default_numeric_fallback_f64.rs:67:21
|
||||
|
|
||||
LL | let y = 1.;
|
||||
| ^^ help: consider adding suffix: `1.0_f64`
|
||||
|
||||
error: default numeric fallback might occur
|
||||
--> $DIR/default_numeric_fallback_f64.rs:78:9
|
||||
--> $DIR/default_numeric_fallback_f64.rs:79:9
|
||||
|
|
||||
LL | 1.
|
||||
| ^^ help: consider adding suffix: `1.0_f64`
|
||||
|
||||
error: default numeric fallback might occur
|
||||
--> $DIR/default_numeric_fallback_f64.rs:84:27
|
||||
--> $DIR/default_numeric_fallback_f64.rs:85:27
|
||||
|
|
||||
LL | let f = || -> _ { 1. };
|
||||
| ^^ help: consider adding suffix: `1.0_f64`
|
||||
|
||||
error: default numeric fallback might occur
|
||||
--> $DIR/default_numeric_fallback_f64.rs:88:29
|
||||
--> $DIR/default_numeric_fallback_f64.rs:89:29
|
||||
|
|
||||
LL | let f = || -> f64 { 1. };
|
||||
| ^^ help: consider adding suffix: `1.0_f64`
|
||||
|
||||
error: default numeric fallback might occur
|
||||
--> $DIR/default_numeric_fallback_f64.rs:102:21
|
||||
--> $DIR/default_numeric_fallback_f64.rs:103:21
|
||||
|
|
||||
LL | generic_arg(1.);
|
||||
| ^^ help: consider adding suffix: `1.0_f64`
|
||||
|
||||
error: default numeric fallback might occur
|
||||
--> $DIR/default_numeric_fallback_f64.rs:105:32
|
||||
--> $DIR/default_numeric_fallback_f64.rs:106:32
|
||||
|
|
||||
LL | let x: _ = generic_arg(1.);
|
||||
| ^^ help: consider adding suffix: `1.0_f64`
|
||||
|
||||
error: default numeric fallback might occur
|
||||
--> $DIR/default_numeric_fallback_f64.rs:123:28
|
||||
--> $DIR/default_numeric_fallback_f64.rs:124:28
|
||||
|
|
||||
LL | GenericStruct { x: 1. };
|
||||
| ^^ help: consider adding suffix: `1.0_f64`
|
||||
|
||||
error: default numeric fallback might occur
|
||||
--> $DIR/default_numeric_fallback_f64.rs:126:36
|
||||
--> $DIR/default_numeric_fallback_f64.rs:127:36
|
||||
|
|
||||
LL | let _ = GenericStruct { x: 1. };
|
||||
| ^^ help: consider adding suffix: `1.0_f64`
|
||||
|
||||
error: default numeric fallback might occur
|
||||
--> $DIR/default_numeric_fallback_f64.rs:144:24
|
||||
--> $DIR/default_numeric_fallback_f64.rs:145:24
|
||||
|
|
||||
LL | GenericEnum::X(1.);
|
||||
| ^^ help: consider adding suffix: `1.0_f64`
|
||||
|
||||
error: default numeric fallback might occur
|
||||
--> $DIR/default_numeric_fallback_f64.rs:164:23
|
||||
--> $DIR/default_numeric_fallback_f64.rs:165:23
|
||||
|
|
||||
LL | s.generic_arg(1.);
|
||||
| ^^ help: consider adding suffix: `1.0_f64`
|
||||
|
||||
error: default numeric fallback might occur
|
||||
--> $DIR/default_numeric_fallback_f64.rs:171:21
|
||||
--> $DIR/default_numeric_fallback_f64.rs:172:21
|
||||
|
|
||||
LL | let x = 22.;
|
||||
| ^^^ help: consider adding suffix: `22.0_f64`
|
||||
|
|
|
@ -9,7 +9,8 @@
|
|||
clippy::no_effect,
|
||||
clippy::unnecessary_operation,
|
||||
clippy::branches_sharing_code,
|
||||
clippy::let_unit_value
|
||||
clippy::let_unit_value,
|
||||
clippy::let_with_type_underscore
|
||||
)]
|
||||
|
||||
#[macro_use]
|
||||
|
|
|
@ -9,7 +9,8 @@
|
|||
clippy::no_effect,
|
||||
clippy::unnecessary_operation,
|
||||
clippy::branches_sharing_code,
|
||||
clippy::let_unit_value
|
||||
clippy::let_unit_value,
|
||||
clippy::let_with_type_underscore
|
||||
)]
|
||||
|
||||
#[macro_use]
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
error: default numeric fallback might occur
|
||||
--> $DIR/default_numeric_fallback_i32.rs:21:17
|
||||
--> $DIR/default_numeric_fallback_i32.rs:22:17
|
||||
|
|
||||
LL | let x = 22;
|
||||
| ^^ help: consider adding suffix: `22_i32`
|
||||
|
@ -7,151 +7,151 @@ LL | let x = 22;
|
|||
= note: `-D clippy::default-numeric-fallback` implied by `-D warnings`
|
||||
|
||||
error: default numeric fallback might occur
|
||||
--> $DIR/default_numeric_fallback_i32.rs:22:18
|
||||
--> $DIR/default_numeric_fallback_i32.rs:23:18
|
||||
|
|
||||
LL | let x = [1, 2, 3];
|
||||
| ^ help: consider adding suffix: `1_i32`
|
||||
|
||||
error: default numeric fallback might occur
|
||||
--> $DIR/default_numeric_fallback_i32.rs:22:21
|
||||
--> $DIR/default_numeric_fallback_i32.rs:23:21
|
||||
|
|
||||
LL | let x = [1, 2, 3];
|
||||
| ^ help: consider adding suffix: `2_i32`
|
||||
|
||||
error: default numeric fallback might occur
|
||||
--> $DIR/default_numeric_fallback_i32.rs:22:24
|
||||
--> $DIR/default_numeric_fallback_i32.rs:23:24
|
||||
|
|
||||
LL | let x = [1, 2, 3];
|
||||
| ^ help: consider adding suffix: `3_i32`
|
||||
|
||||
error: default numeric fallback might occur
|
||||
--> $DIR/default_numeric_fallback_i32.rs:23:28
|
||||
--> $DIR/default_numeric_fallback_i32.rs:24:28
|
||||
|
|
||||
LL | let x = if true { (1, 2) } else { (3, 4) };
|
||||
| ^ help: consider adding suffix: `1_i32`
|
||||
|
||||
error: default numeric fallback might occur
|
||||
--> $DIR/default_numeric_fallback_i32.rs:23:31
|
||||
--> $DIR/default_numeric_fallback_i32.rs:24:31
|
||||
|
|
||||
LL | let x = if true { (1, 2) } else { (3, 4) };
|
||||
| ^ help: consider adding suffix: `2_i32`
|
||||
|
||||
error: default numeric fallback might occur
|
||||
--> $DIR/default_numeric_fallback_i32.rs:23:44
|
||||
--> $DIR/default_numeric_fallback_i32.rs:24:44
|
||||
|
|
||||
LL | let x = if true { (1, 2) } else { (3, 4) };
|
||||
| ^ help: consider adding suffix: `3_i32`
|
||||
|
||||
error: default numeric fallback might occur
|
||||
--> $DIR/default_numeric_fallback_i32.rs:23:47
|
||||
--> $DIR/default_numeric_fallback_i32.rs:24:47
|
||||
|
|
||||
LL | let x = if true { (1, 2) } else { (3, 4) };
|
||||
| ^ help: consider adding suffix: `4_i32`
|
||||
|
||||
error: default numeric fallback might occur
|
||||
--> $DIR/default_numeric_fallback_i32.rs:24:23
|
||||
--> $DIR/default_numeric_fallback_i32.rs:25:23
|
||||
|
|
||||
LL | let x = match 1 {
|
||||
| ^ help: consider adding suffix: `1_i32`
|
||||
|
||||
error: default numeric fallback might occur
|
||||
--> $DIR/default_numeric_fallback_i32.rs:25:13
|
||||
--> $DIR/default_numeric_fallback_i32.rs:26:13
|
||||
|
|
||||
LL | 1 => 1,
|
||||
| ^ help: consider adding suffix: `1_i32`
|
||||
|
||||
error: default numeric fallback might occur
|
||||
--> $DIR/default_numeric_fallback_i32.rs:25:18
|
||||
--> $DIR/default_numeric_fallback_i32.rs:26:18
|
||||
|
|
||||
LL | 1 => 1,
|
||||
| ^ help: consider adding suffix: `1_i32`
|
||||
|
||||
error: default numeric fallback might occur
|
||||
--> $DIR/default_numeric_fallback_i32.rs:26:18
|
||||
--> $DIR/default_numeric_fallback_i32.rs:27:18
|
||||
|
|
||||
LL | _ => 2,
|
||||
| ^ help: consider adding suffix: `2_i32`
|
||||
|
||||
error: default numeric fallback might occur
|
||||
--> $DIR/default_numeric_fallback_i32.rs:45:21
|
||||
--> $DIR/default_numeric_fallback_i32.rs:46:21
|
||||
|
|
||||
LL | let y = 1;
|
||||
| ^ help: consider adding suffix: `1_i32`
|
||||
|
||||
error: default numeric fallback might occur
|
||||
--> $DIR/default_numeric_fallback_i32.rs:53:21
|
||||
--> $DIR/default_numeric_fallback_i32.rs:54:21
|
||||
|
|
||||
LL | let y = 1;
|
||||
| ^ help: consider adding suffix: `1_i32`
|
||||
|
||||
error: default numeric fallback might occur
|
||||
--> $DIR/default_numeric_fallback_i32.rs:59:21
|
||||
--> $DIR/default_numeric_fallback_i32.rs:60:21
|
||||
|
|
||||
LL | let y = 1;
|
||||
| ^ help: consider adding suffix: `1_i32`
|
||||
|
||||
error: default numeric fallback might occur
|
||||
--> $DIR/default_numeric_fallback_i32.rs:67:21
|
||||
--> $DIR/default_numeric_fallback_i32.rs:68:21
|
||||
|
|
||||
LL | let y = 1;
|
||||
| ^ help: consider adding suffix: `1_i32`
|
||||
|
||||
error: default numeric fallback might occur
|
||||
--> $DIR/default_numeric_fallback_i32.rs:79:9
|
||||
--> $DIR/default_numeric_fallback_i32.rs:80:9
|
||||
|
|
||||
LL | 1
|
||||
| ^ help: consider adding suffix: `1_i32`
|
||||
|
||||
error: default numeric fallback might occur
|
||||
--> $DIR/default_numeric_fallback_i32.rs:85:27
|
||||
--> $DIR/default_numeric_fallback_i32.rs:86:27
|
||||
|
|
||||
LL | let f = || -> _ { 1 };
|
||||
| ^ help: consider adding suffix: `1_i32`
|
||||
|
||||
error: default numeric fallback might occur
|
||||
--> $DIR/default_numeric_fallback_i32.rs:89:29
|
||||
--> $DIR/default_numeric_fallback_i32.rs:90:29
|
||||
|
|
||||
LL | let f = || -> i32 { 1 };
|
||||
| ^ help: consider adding suffix: `1_i32`
|
||||
|
||||
error: default numeric fallback might occur
|
||||
--> $DIR/default_numeric_fallback_i32.rs:103:21
|
||||
--> $DIR/default_numeric_fallback_i32.rs:104:21
|
||||
|
|
||||
LL | generic_arg(1);
|
||||
| ^ help: consider adding suffix: `1_i32`
|
||||
|
||||
error: default numeric fallback might occur
|
||||
--> $DIR/default_numeric_fallback_i32.rs:106:32
|
||||
--> $DIR/default_numeric_fallback_i32.rs:107:32
|
||||
|
|
||||
LL | let x: _ = generic_arg(1);
|
||||
| ^ help: consider adding suffix: `1_i32`
|
||||
|
||||
error: default numeric fallback might occur
|
||||
--> $DIR/default_numeric_fallback_i32.rs:124:28
|
||||
--> $DIR/default_numeric_fallback_i32.rs:125:28
|
||||
|
|
||||
LL | GenericStruct { x: 1 };
|
||||
| ^ help: consider adding suffix: `1_i32`
|
||||
|
||||
error: default numeric fallback might occur
|
||||
--> $DIR/default_numeric_fallback_i32.rs:127:36
|
||||
--> $DIR/default_numeric_fallback_i32.rs:128:36
|
||||
|
|
||||
LL | let _ = GenericStruct { x: 1 };
|
||||
| ^ help: consider adding suffix: `1_i32`
|
||||
|
||||
error: default numeric fallback might occur
|
||||
--> $DIR/default_numeric_fallback_i32.rs:145:24
|
||||
--> $DIR/default_numeric_fallback_i32.rs:146:24
|
||||
|
|
||||
LL | GenericEnum::X(1);
|
||||
| ^ help: consider adding suffix: `1_i32`
|
||||
|
||||
error: default numeric fallback might occur
|
||||
--> $DIR/default_numeric_fallback_i32.rs:165:23
|
||||
--> $DIR/default_numeric_fallback_i32.rs:166:23
|
||||
|
|
||||
LL | s.generic_arg(1);
|
||||
| ^ help: consider adding suffix: `1_i32`
|
||||
|
||||
error: default numeric fallback might occur
|
||||
--> $DIR/default_numeric_fallback_i32.rs:172:21
|
||||
--> $DIR/default_numeric_fallback_i32.rs:173:21
|
||||
|
|
||||
LL | let x = 22;
|
||||
| ^^ help: consider adding suffix: `22_i32`
|
||||
|
|
|
@ -231,4 +231,41 @@ impl Default for NonExhaustiveEnum {
|
|||
}
|
||||
}
|
||||
|
||||
// https://github.com/rust-lang/rust-clippy/issues/10396
|
||||
|
||||
#[derive(Default)]
|
||||
struct DefaultType;
|
||||
|
||||
struct GenericType<T = DefaultType> {
|
||||
t: T,
|
||||
}
|
||||
|
||||
impl Default for GenericType {
|
||||
fn default() -> Self {
|
||||
Self { t: Default::default() }
|
||||
}
|
||||
}
|
||||
|
||||
struct InnerGenericType<T> {
|
||||
t: T,
|
||||
}
|
||||
|
||||
impl Default for InnerGenericType<DefaultType> {
|
||||
fn default() -> Self {
|
||||
Self { t: Default::default() }
|
||||
}
|
||||
}
|
||||
|
||||
struct OtherGenericType<T = DefaultType> {
|
||||
inner: InnerGenericType<T>,
|
||||
}
|
||||
|
||||
impl Default for OtherGenericType {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
inner: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
@ -267,4 +267,41 @@ impl Default for NonExhaustiveEnum {
|
|||
}
|
||||
}
|
||||
|
||||
// https://github.com/rust-lang/rust-clippy/issues/10396
|
||||
|
||||
#[derive(Default)]
|
||||
struct DefaultType;
|
||||
|
||||
struct GenericType<T = DefaultType> {
|
||||
t: T,
|
||||
}
|
||||
|
||||
impl Default for GenericType {
|
||||
fn default() -> Self {
|
||||
Self { t: Default::default() }
|
||||
}
|
||||
}
|
||||
|
||||
struct InnerGenericType<T> {
|
||||
t: T,
|
||||
}
|
||||
|
||||
impl Default for InnerGenericType<DefaultType> {
|
||||
fn default() -> Self {
|
||||
Self { t: Default::default() }
|
||||
}
|
||||
}
|
||||
|
||||
struct OtherGenericType<T = DefaultType> {
|
||||
inner: InnerGenericType<T>,
|
||||
}
|
||||
|
||||
impl Default for OtherGenericType {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
inner: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
// run-rustfix
|
||||
// aux-build: proc_macro_with_span.rs
|
||||
#![warn(clippy::useless_format)]
|
||||
#![allow(
|
||||
unused_tuple_struct_fields,
|
||||
|
@ -10,8 +9,6 @@
|
|||
clippy::uninlined_format_args
|
||||
)]
|
||||
|
||||
extern crate proc_macro_with_span;
|
||||
|
||||
struct Foo(pub String);
|
||||
|
||||
macro_rules! foo {
|
||||
|
@ -90,7 +87,4 @@ fn main() {
|
|||
let _ = abc.to_string();
|
||||
let xx = "xx";
|
||||
let _ = xx.to_string();
|
||||
|
||||
// Issue #10148
|
||||
println!(proc_macro_with_span::with_span!(""something ""));
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
// run-rustfix
|
||||
// aux-build: proc_macro_with_span.rs
|
||||
#![warn(clippy::useless_format)]
|
||||
#![allow(
|
||||
unused_tuple_struct_fields,
|
||||
|
@ -10,8 +9,6 @@
|
|||
clippy::uninlined_format_args
|
||||
)]
|
||||
|
||||
extern crate proc_macro_with_span;
|
||||
|
||||
struct Foo(pub String);
|
||||
|
||||
macro_rules! foo {
|
||||
|
@ -92,7 +89,4 @@ fn main() {
|
|||
let _ = format!("{abc}");
|
||||
let xx = "xx";
|
||||
let _ = format!("{xx}");
|
||||
|
||||
// Issue #10148
|
||||
println!(proc_macro_with_span::with_span!(""something ""));
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
error: useless use of `format!`
|
||||
--> $DIR/format.rs:22:5
|
||||
--> $DIR/format.rs:19:5
|
||||
|
|
||||
LL | format!("foo");
|
||||
| ^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()`
|
||||
|
@ -7,19 +7,19 @@ LL | format!("foo");
|
|||
= note: `-D clippy::useless-format` implied by `-D warnings`
|
||||
|
||||
error: useless use of `format!`
|
||||
--> $DIR/format.rs:23:5
|
||||
--> $DIR/format.rs:20:5
|
||||
|
|
||||
LL | format!("{{}}");
|
||||
| ^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"{}".to_string()`
|
||||
|
||||
error: useless use of `format!`
|
||||
--> $DIR/format.rs:24:5
|
||||
--> $DIR/format.rs:21:5
|
||||
|
|
||||
LL | format!("{{}} abc {{}}");
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"{} abc {}".to_string()`
|
||||
|
||||
error: useless use of `format!`
|
||||
--> $DIR/format.rs:25:5
|
||||
--> $DIR/format.rs:22:5
|
||||
|
|
||||
LL | / format!(
|
||||
LL | | r##"foo {{}}
|
||||
|
@ -34,67 +34,67 @@ LL ~ " bar"##.to_string();
|
|||
|
|
||||
|
||||
error: useless use of `format!`
|
||||
--> $DIR/format.rs:30:13
|
||||
--> $DIR/format.rs:27:13
|
||||
|
|
||||
LL | let _ = format!("");
|
||||
| ^^^^^^^^^^^ help: consider using `String::new()`: `String::new()`
|
||||
|
||||
error: useless use of `format!`
|
||||
--> $DIR/format.rs:32:5
|
||||
--> $DIR/format.rs:29:5
|
||||
|
|
||||
LL | format!("{}", "foo");
|
||||
| ^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()`
|
||||
|
||||
error: useless use of `format!`
|
||||
--> $DIR/format.rs:40:5
|
||||
--> $DIR/format.rs:37:5
|
||||
|
|
||||
LL | format!("{}", arg);
|
||||
| ^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string()`
|
||||
|
||||
error: useless use of `format!`
|
||||
--> $DIR/format.rs:70:5
|
||||
--> $DIR/format.rs:67:5
|
||||
|
|
||||
LL | format!("{}", 42.to_string());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `42.to_string()`
|
||||
|
||||
error: useless use of `format!`
|
||||
--> $DIR/format.rs:72:5
|
||||
--> $DIR/format.rs:69:5
|
||||
|
|
||||
LL | format!("{}", x.display().to_string());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.display().to_string()`
|
||||
|
||||
error: useless use of `format!`
|
||||
--> $DIR/format.rs:76:18
|
||||
--> $DIR/format.rs:73:18
|
||||
|
|
||||
LL | let _ = Some(format!("{}", a + "bar"));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `a + "bar"`
|
||||
|
||||
error: useless use of `format!`
|
||||
--> $DIR/format.rs:80:22
|
||||
--> $DIR/format.rs:77:22
|
||||
|
|
||||
LL | let _s: String = format!("{}", &*v.join("/n"));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `(&*v.join("/n")).to_string()`
|
||||
|
||||
error: useless use of `format!`
|
||||
--> $DIR/format.rs:86:13
|
||||
--> $DIR/format.rs:83:13
|
||||
|
|
||||
LL | let _ = format!("{x}");
|
||||
| ^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.to_string()`
|
||||
|
||||
error: useless use of `format!`
|
||||
--> $DIR/format.rs:88:13
|
||||
--> $DIR/format.rs:85:13
|
||||
|
|
||||
LL | let _ = format!("{y}", y = x);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.to_string()`
|
||||
|
||||
error: useless use of `format!`
|
||||
--> $DIR/format.rs:92:13
|
||||
--> $DIR/format.rs:89:13
|
||||
|
|
||||
LL | let _ = format!("{abc}");
|
||||
| ^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `abc.to_string()`
|
||||
|
||||
error: useless use of `format!`
|
||||
--> $DIR/format.rs:94:13
|
||||
--> $DIR/format.rs:91:13
|
||||
|
|
||||
LL | let _ = format!("{xx}");
|
||||
| ^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `xx.to_string()`
|
||||
|
|
|
@ -5,7 +5,7 @@ LL | pub fn a(_: impl Trait) {}
|
|||
| ^^^^^^^^^^
|
||||
|
|
||||
= note: `-D clippy::impl-trait-in-params` implied by `-D warnings`
|
||||
help: add a type paremeter
|
||||
help: add a type parameter
|
||||
|
|
||||
LL | pub fn a<{ /* Generic name */ }: Trait>(_: impl Trait) {}
|
||||
| +++++++++++++++++++++++++++++++
|
||||
|
@ -16,7 +16,7 @@ error: '`impl Trait` used as a function parameter'
|
|||
LL | pub fn c<C: Trait>(_: C, _: impl Trait) {}
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
help: add a type paremeter
|
||||
help: add a type parameter
|
||||
|
|
||||
LL | pub fn c<C: Trait, { /* Generic name */ }: Trait>(_: C, _: impl Trait) {}
|
||||
| +++++++++++++++++++++++++++++++
|
||||
|
|
|
@ -87,7 +87,7 @@ fn main() {
|
|||
let kitten = Kitten {};
|
||||
let _ = kitten.clone();
|
||||
let _ = own_same_from_ref(&kitten);
|
||||
// this shouln't lint
|
||||
// this shouldn't lint
|
||||
let _ = kitten.to_vec();
|
||||
|
||||
// we expect no lints for this
|
||||
|
|
|
@ -87,7 +87,7 @@ fn main() {
|
|||
let kitten = Kitten {};
|
||||
let _ = kitten.to_owned();
|
||||
let _ = own_same_from_ref(&kitten);
|
||||
// this shouln't lint
|
||||
// this shouldn't lint
|
||||
let _ = kitten.to_vec();
|
||||
|
||||
// we expect no lints for this
|
||||
|
|
|
@ -282,6 +282,87 @@ impl AsyncLen {
|
|||
}
|
||||
}
|
||||
|
||||
// issue #7232
|
||||
pub struct AsyncLenWithoutIsEmpty;
|
||||
impl AsyncLenWithoutIsEmpty {
|
||||
pub async fn async_task(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
pub async fn len(&self) -> usize {
|
||||
usize::from(!self.async_task().await)
|
||||
}
|
||||
}
|
||||
|
||||
// issue #7232
|
||||
pub struct AsyncOptionLenWithoutIsEmpty;
|
||||
impl AsyncOptionLenWithoutIsEmpty {
|
||||
async fn async_task(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
pub async fn len(&self) -> Option<usize> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
// issue #7232
|
||||
pub struct AsyncOptionLenNonIntegral;
|
||||
impl AsyncOptionLenNonIntegral {
|
||||
// don't lint
|
||||
pub async fn len(&self) -> Option<String> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
// issue #7232
|
||||
pub struct AsyncResultLenWithoutIsEmpty;
|
||||
impl AsyncResultLenWithoutIsEmpty {
|
||||
async fn async_task(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
pub async fn len(&self) -> Result<usize, ()> {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
|
||||
// issue #7232
|
||||
pub struct AsyncOptionLen;
|
||||
impl AsyncOptionLen {
|
||||
async fn async_task(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
pub async fn len(&self) -> Result<usize, ()> {
|
||||
Err(())
|
||||
}
|
||||
|
||||
pub async fn is_empty(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AsyncLenSyncIsEmpty;
|
||||
impl AsyncLenSyncIsEmpty {
|
||||
pub async fn len(&self) -> u32 {
|
||||
0
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
// issue #9520
|
||||
pub struct NonStandardLen;
|
||||
impl NonStandardLen {
|
||||
// don't lint
|
||||
pub fn len(&self, something: usize) -> usize {
|
||||
something
|
||||
}
|
||||
}
|
||||
|
||||
// issue #9520
|
||||
pub struct NonStandardLenAndIsEmptySignature;
|
||||
impl NonStandardLenAndIsEmptySignature {
|
||||
|
@ -328,4 +409,15 @@ impl NonStandardSignatureWithGenerics {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct DifferingErrors;
|
||||
impl DifferingErrors {
|
||||
pub fn len(&self) -> Result<usize, u8> {
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> Result<bool, u16> {
|
||||
Ok(true)
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
@ -119,5 +119,23 @@ LL | pub fn len(&self) -> Result<usize, ()> {
|
|||
|
|
||||
= help: use a custom `Error` type instead
|
||||
|
||||
error: aborting due to 12 previous errors
|
||||
error: struct `AsyncLenWithoutIsEmpty` has a public `len` method, but no `is_empty` method
|
||||
--> $DIR/len_without_is_empty.rs:292:5
|
||||
|
|
||||
LL | pub async fn len(&self) -> usize {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: struct `AsyncOptionLenWithoutIsEmpty` has a public `len` method, but no `is_empty` method
|
||||
--> $DIR/len_without_is_empty.rs:304:5
|
||||
|
|
||||
LL | pub async fn len(&self) -> Option<usize> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: struct `AsyncResultLenWithoutIsEmpty` has a public `len` method, but no `is_empty` method
|
||||
--> $DIR/len_without_is_empty.rs:325:5
|
||||
|
|
||||
LL | pub async fn len(&self) -> Result<usize, ()> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 15 previous errors
|
||||
|
||||
|
|
|
@ -175,3 +175,7 @@ fn attributes() {
|
|||
#[expect(clippy::let_unit_value)]
|
||||
let _ = f();
|
||||
}
|
||||
|
||||
async fn issue10433() {
|
||||
let _pending: () = std::future::pending().await;
|
||||
}
|
||||
|
|
|
@ -175,3 +175,7 @@ fn attributes() {
|
|||
#[expect(clippy::let_unit_value)]
|
||||
let _ = f();
|
||||
}
|
||||
|
||||
async fn issue10433() {
|
||||
let _pending: () = std::future::pending().await;
|
||||
}
|
||||
|
|
19
tests/ui/let_with_type_underscore.rs
Normal file
19
tests/ui/let_with_type_underscore.rs
Normal file
|
@ -0,0 +1,19 @@
|
|||
#![allow(unused)]
|
||||
#![warn(clippy::let_with_type_underscore)]
|
||||
#![allow(clippy::let_unit_value)]
|
||||
|
||||
fn func() -> &'static str {
|
||||
""
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// Will lint
|
||||
let x: _ = 1;
|
||||
let _: _ = 2;
|
||||
let x: _ = func();
|
||||
|
||||
let x = 1; // Will not lint, Rust inferres this to an integer before Clippy
|
||||
let x = func();
|
||||
let x: Vec<_> = Vec::<u32>::new();
|
||||
let x: [_; 1] = [1];
|
||||
}
|
39
tests/ui/let_with_type_underscore.stderr
Normal file
39
tests/ui/let_with_type_underscore.stderr
Normal file
|
@ -0,0 +1,39 @@
|
|||
error: variable declared with type underscore
|
||||
--> $DIR/let_with_type_underscore.rs:11:5
|
||||
|
|
||||
LL | let x: _ = 1;
|
||||
| ^^^^^^^^^^^^^
|
||||
|
|
||||
help: remove the explicit type `_` declaration
|
||||
--> $DIR/let_with_type_underscore.rs:11:10
|
||||
|
|
||||
LL | let x: _ = 1;
|
||||
| ^^^
|
||||
= note: `-D clippy::let-with-type-underscore` implied by `-D warnings`
|
||||
|
||||
error: variable declared with type underscore
|
||||
--> $DIR/let_with_type_underscore.rs:12:5
|
||||
|
|
||||
LL | let _: _ = 2;
|
||||
| ^^^^^^^^^^^^^
|
||||
|
|
||||
help: remove the explicit type `_` declaration
|
||||
--> $DIR/let_with_type_underscore.rs:12:10
|
||||
|
|
||||
LL | let _: _ = 2;
|
||||
| ^^^
|
||||
|
||||
error: variable declared with type underscore
|
||||
--> $DIR/let_with_type_underscore.rs:13:5
|
||||
|
|
||||
LL | let x: _ = func();
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: remove the explicit type `_` declaration
|
||||
--> $DIR/let_with_type_underscore.rs:13:10
|
||||
|
|
||||
LL | let x: _ = func();
|
||||
| ^^^
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
// aux-build:macro_rules.rs
|
||||
|
||||
#![warn(clippy::manual_rem_euclid)]
|
||||
#![allow(clippy::let_with_type_underscore)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate macro_rules;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// aux-build:macro_rules.rs
|
||||
|
||||
#![warn(clippy::manual_rem_euclid)]
|
||||
#![allow(clippy::let_with_type_underscore)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate macro_rules;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
error: manual `rem_euclid` implementation
|
||||
--> $DIR/manual_rem_euclid.rs:19:18
|
||||
--> $DIR/manual_rem_euclid.rs:20:18
|
||||
|
|
||||
LL | let _: i32 = ((value % 4) + 4) % 4;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `value.rem_euclid(4)`
|
||||
|
@ -7,31 +7,31 @@ LL | let _: i32 = ((value % 4) + 4) % 4;
|
|||
= note: `-D clippy::manual-rem-euclid` implied by `-D warnings`
|
||||
|
||||
error: manual `rem_euclid` implementation
|
||||
--> $DIR/manual_rem_euclid.rs:20:18
|
||||
--> $DIR/manual_rem_euclid.rs:21:18
|
||||
|
|
||||
LL | let _: i32 = (4 + (value % 4)) % 4;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `value.rem_euclid(4)`
|
||||
|
||||
error: manual `rem_euclid` implementation
|
||||
--> $DIR/manual_rem_euclid.rs:21:18
|
||||
--> $DIR/manual_rem_euclid.rs:22:18
|
||||
|
|
||||
LL | let _: i32 = (value % 4 + 4) % 4;
|
||||
| ^^^^^^^^^^^^^^^^^^^ help: consider using: `value.rem_euclid(4)`
|
||||
|
||||
error: manual `rem_euclid` implementation
|
||||
--> $DIR/manual_rem_euclid.rs:22:18
|
||||
--> $DIR/manual_rem_euclid.rs:23:18
|
||||
|
|
||||
LL | let _: i32 = (4 + value % 4) % 4;
|
||||
| ^^^^^^^^^^^^^^^^^^^ help: consider using: `value.rem_euclid(4)`
|
||||
|
||||
error: manual `rem_euclid` implementation
|
||||
--> $DIR/manual_rem_euclid.rs:23:22
|
||||
--> $DIR/manual_rem_euclid.rs:24:22
|
||||
|
|
||||
LL | let _: i32 = 1 + (4 + value % 4) % 4;
|
||||
| ^^^^^^^^^^^^^^^^^^^ help: consider using: `value.rem_euclid(4)`
|
||||
|
||||
error: manual `rem_euclid` implementation
|
||||
--> $DIR/manual_rem_euclid.rs:12:22
|
||||
--> $DIR/manual_rem_euclid.rs:13:22
|
||||
|
|
||||
LL | let _: i32 = ((value % 4) + 4) % 4;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `value.rem_euclid(4)`
|
||||
|
@ -42,25 +42,25 @@ LL | internal_rem_euclid!();
|
|||
= note: this error originates in the macro `internal_rem_euclid` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: manual `rem_euclid` implementation
|
||||
--> $DIR/manual_rem_euclid.rs:49:5
|
||||
--> $DIR/manual_rem_euclid.rs:50:5
|
||||
|
|
||||
LL | ((num % 4) + 4) % 4
|
||||
| ^^^^^^^^^^^^^^^^^^^ help: consider using: `num.rem_euclid(4)`
|
||||
|
||||
error: manual `rem_euclid` implementation
|
||||
--> $DIR/manual_rem_euclid.rs:54:5
|
||||
--> $DIR/manual_rem_euclid.rs:55:5
|
||||
|
|
||||
LL | ((num % 4) + 4) % 4
|
||||
| ^^^^^^^^^^^^^^^^^^^ help: consider using: `num.rem_euclid(4)`
|
||||
|
||||
error: manual `rem_euclid` implementation
|
||||
--> $DIR/manual_rem_euclid.rs:66:18
|
||||
--> $DIR/manual_rem_euclid.rs:67:18
|
||||
|
|
||||
LL | let _: i32 = ((x % 4) + 4) % 4;
|
||||
| ^^^^^^^^^^^^^^^^^ help: consider using: `x.rem_euclid(4)`
|
||||
|
||||
error: manual `rem_euclid` implementation
|
||||
--> $DIR/manual_rem_euclid.rs:79:18
|
||||
--> $DIR/manual_rem_euclid.rs:80:18
|
||||
|
|
||||
LL | let _: i32 = ((x % 4) + 4) % 4;
|
||||
| ^^^^^^^^^^^^^^^^^ help: consider using: `x.rem_euclid(4)`
|
||||
|
|
|
@ -16,7 +16,7 @@ fn str_to_int_ok(x: &str) -> i32 {
|
|||
#[rustfmt::skip]
|
||||
fn strange_some_no_else(x: &str) -> i32 {
|
||||
{
|
||||
if let Ok(y) = x . parse() {
|
||||
if let Ok(y) = x . parse() {
|
||||
return y;
|
||||
};
|
||||
0
|
||||
|
|
|
@ -18,7 +18,7 @@ LL | if let Some(y) = x . parse() . ok () {
|
|||
|
|
||||
help: consider matching on `Ok(y)` and removing the call to `ok` instead
|
||||
|
|
||||
LL | if let Ok(y) = x . parse() {
|
||||
LL | if let Ok(y) = x . parse() {
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
error: matching on `Some` with `ok()` is redundant
|
||||
|
|
84
tests/ui/missing_assert_message.rs
Normal file
84
tests/ui/missing_assert_message.rs
Normal file
|
@ -0,0 +1,84 @@
|
|||
#![allow(unused)]
|
||||
#![warn(clippy::missing_assert_message)]
|
||||
|
||||
macro_rules! bar {
|
||||
($( $x:expr ),*) => {
|
||||
foo()
|
||||
};
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
||||
// Should trigger warning
|
||||
fn asserts_without_message() {
|
||||
assert!(foo());
|
||||
assert_eq!(foo(), foo());
|
||||
assert_ne!(foo(), foo());
|
||||
debug_assert!(foo());
|
||||
debug_assert_eq!(foo(), foo());
|
||||
debug_assert_ne!(foo(), foo());
|
||||
}
|
||||
|
||||
// Should trigger warning
|
||||
fn asserts_without_message_but_with_macro_calls() {
|
||||
assert!(bar!(true));
|
||||
assert!(bar!(true, false));
|
||||
assert_eq!(bar!(true), foo());
|
||||
assert_ne!(bar!(true, true), bar!(true));
|
||||
}
|
||||
|
||||
// Should trigger warning
|
||||
fn asserts_with_trailing_commas() {
|
||||
assert!(foo(),);
|
||||
assert_eq!(foo(), foo(),);
|
||||
assert_ne!(foo(), foo(),);
|
||||
debug_assert!(foo(),);
|
||||
debug_assert_eq!(foo(), foo(),);
|
||||
debug_assert_ne!(foo(), foo(),);
|
||||
}
|
||||
|
||||
// Should not trigger warning
|
||||
fn asserts_with_message_and_with_macro_calls() {
|
||||
assert!(bar!(true), "msg");
|
||||
assert!(bar!(true, false), "msg");
|
||||
assert_eq!(bar!(true), foo(), "msg");
|
||||
assert_ne!(bar!(true, true), bar!(true), "msg");
|
||||
}
|
||||
|
||||
// Should not trigger warning
|
||||
fn asserts_with_message() {
|
||||
assert!(foo(), "msg");
|
||||
assert_eq!(foo(), foo(), "msg");
|
||||
assert_ne!(foo(), foo(), "msg");
|
||||
debug_assert!(foo(), "msg");
|
||||
debug_assert_eq!(foo(), foo(), "msg");
|
||||
debug_assert_ne!(foo(), foo(), "msg");
|
||||
}
|
||||
|
||||
// Should not trigger warning
|
||||
#[test]
|
||||
fn asserts_without_message_but_inside_a_test_function() {
|
||||
assert!(foo());
|
||||
assert_eq!(foo(), foo());
|
||||
assert_ne!(foo(), foo());
|
||||
debug_assert!(foo());
|
||||
debug_assert_eq!(foo(), foo());
|
||||
debug_assert_ne!(foo(), foo());
|
||||
}
|
||||
|
||||
// Should not trigger warning
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
fn asserts_without_message_but_inside_a_test_module() {
|
||||
assert!(foo());
|
||||
assert_eq!(foo(), foo());
|
||||
assert_ne!(foo(), foo());
|
||||
debug_assert!(foo());
|
||||
debug_assert_eq!(foo(), foo());
|
||||
debug_assert_ne!(foo(), foo());
|
||||
}
|
||||
}
|
||||
|
||||
fn foo() -> bool {
|
||||
true
|
||||
}
|
131
tests/ui/missing_assert_message.stderr
Normal file
131
tests/ui/missing_assert_message.stderr
Normal file
|
@ -0,0 +1,131 @@
|
|||
error: assert without any message
|
||||
--> $DIR/missing_assert_message.rs:14:5
|
||||
|
|
||||
LL | assert!(foo());
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: consider describing why the failing assert is problematic
|
||||
= note: `-D clippy::missing-assert-message` implied by `-D warnings`
|
||||
|
||||
error: assert without any message
|
||||
--> $DIR/missing_assert_message.rs:15:5
|
||||
|
|
||||
LL | assert_eq!(foo(), foo());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: consider describing why the failing assert is problematic
|
||||
|
||||
error: assert without any message
|
||||
--> $DIR/missing_assert_message.rs:16:5
|
||||
|
|
||||
LL | assert_ne!(foo(), foo());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: consider describing why the failing assert is problematic
|
||||
|
||||
error: assert without any message
|
||||
--> $DIR/missing_assert_message.rs:17:5
|
||||
|
|
||||
LL | debug_assert!(foo());
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: consider describing why the failing assert is problematic
|
||||
|
||||
error: assert without any message
|
||||
--> $DIR/missing_assert_message.rs:18:5
|
||||
|
|
||||
LL | debug_assert_eq!(foo(), foo());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: consider describing why the failing assert is problematic
|
||||
|
||||
error: assert without any message
|
||||
--> $DIR/missing_assert_message.rs:19:5
|
||||
|
|
||||
LL | debug_assert_ne!(foo(), foo());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: consider describing why the failing assert is problematic
|
||||
|
||||
error: assert without any message
|
||||
--> $DIR/missing_assert_message.rs:24:5
|
||||
|
|
||||
LL | assert!(bar!(true));
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: consider describing why the failing assert is problematic
|
||||
|
||||
error: assert without any message
|
||||
--> $DIR/missing_assert_message.rs:25:5
|
||||
|
|
||||
LL | assert!(bar!(true, false));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: consider describing why the failing assert is problematic
|
||||
|
||||
error: assert without any message
|
||||
--> $DIR/missing_assert_message.rs:26:5
|
||||
|
|
||||
LL | assert_eq!(bar!(true), foo());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: consider describing why the failing assert is problematic
|
||||
|
||||
error: assert without any message
|
||||
--> $DIR/missing_assert_message.rs:27:5
|
||||
|
|
||||
LL | assert_ne!(bar!(true, true), bar!(true));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: consider describing why the failing assert is problematic
|
||||
|
||||
error: assert without any message
|
||||
--> $DIR/missing_assert_message.rs:32:5
|
||||
|
|
||||
LL | assert!(foo(),);
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: consider describing why the failing assert is problematic
|
||||
|
||||
error: assert without any message
|
||||
--> $DIR/missing_assert_message.rs:33:5
|
||||
|
|
||||
LL | assert_eq!(foo(), foo(),);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: consider describing why the failing assert is problematic
|
||||
|
||||
error: assert without any message
|
||||
--> $DIR/missing_assert_message.rs:34:5
|
||||
|
|
||||
LL | assert_ne!(foo(), foo(),);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: consider describing why the failing assert is problematic
|
||||
|
||||
error: assert without any message
|
||||
--> $DIR/missing_assert_message.rs:35:5
|
||||
|
|
||||
LL | debug_assert!(foo(),);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: consider describing why the failing assert is problematic
|
||||
|
||||
error: assert without any message
|
||||
--> $DIR/missing_assert_message.rs:36:5
|
||||
|
|
||||
LL | debug_assert_eq!(foo(), foo(),);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: consider describing why the failing assert is problematic
|
||||
|
||||
error: assert without any message
|
||||
--> $DIR/missing_assert_message.rs:37:5
|
||||
|
|
||||
LL | debug_assert_ne!(foo(), foo(),);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: consider describing why the failing assert is problematic
|
||||
|
||||
error: aborting due to 16 previous errors
|
||||
|
|
@ -6,30 +6,12 @@ LL | type Typedef = String;
|
|||
|
|
||||
= note: `-D clippy::missing-docs-in-private-items` implied by `-D warnings`
|
||||
|
||||
error: missing documentation for a type alias
|
||||
--> $DIR/missing_doc.rs:17:1
|
||||
|
|
||||
LL | pub type PubTypedef = String;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: missing documentation for a module
|
||||
--> $DIR/missing_doc.rs:19:1
|
||||
|
|
||||
LL | mod module_no_dox {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: missing documentation for a module
|
||||
--> $DIR/missing_doc.rs:20:1
|
||||
|
|
||||
LL | pub mod pub_module_no_dox {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: missing documentation for a function
|
||||
--> $DIR/missing_doc.rs:24:1
|
||||
|
|
||||
LL | pub fn foo2() {}
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
||||
error: missing documentation for a function
|
||||
--> $DIR/missing_doc.rs:25:1
|
||||
|
|
||||
|
@ -69,50 +51,18 @@ error: missing documentation for a variant
|
|||
LL | BarB,
|
||||
| ^^^^
|
||||
|
||||
error: missing documentation for an enum
|
||||
--> $DIR/missing_doc.rs:44:1
|
||||
|
|
||||
LL | / pub enum PubBaz {
|
||||
LL | | PubBazA { a: isize },
|
||||
LL | | }
|
||||
| |_^
|
||||
|
||||
error: missing documentation for a variant
|
||||
--> $DIR/missing_doc.rs:45:5
|
||||
|
|
||||
LL | PubBazA { a: isize },
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: missing documentation for a struct field
|
||||
--> $DIR/missing_doc.rs:45:15
|
||||
|
|
||||
LL | PubBazA { a: isize },
|
||||
| ^^^^^^^^
|
||||
|
||||
error: missing documentation for a constant
|
||||
--> $DIR/missing_doc.rs:65:1
|
||||
|
|
||||
LL | const FOO: u32 = 0;
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: missing documentation for a constant
|
||||
--> $DIR/missing_doc.rs:72:1
|
||||
|
|
||||
LL | pub const FOO4: u32 = 0;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: missing documentation for a static
|
||||
--> $DIR/missing_doc.rs:74:1
|
||||
|
|
||||
LL | static BAR: u32 = 0;
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: missing documentation for a static
|
||||
--> $DIR/missing_doc.rs:81:1
|
||||
|
|
||||
LL | pub static BAR4: u32 = 0;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: missing documentation for a module
|
||||
--> $DIR/missing_doc.rs:83:1
|
||||
|
|
||||
|
@ -125,35 +75,17 @@ LL | | }
|
|||
LL | | }
|
||||
| |_^
|
||||
|
||||
error: missing documentation for a function
|
||||
--> $DIR/missing_doc.rs:86:5
|
||||
|
|
||||
LL | pub fn undocumented1() {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: missing documentation for a function
|
||||
--> $DIR/missing_doc.rs:87:5
|
||||
|
|
||||
LL | pub fn undocumented2() {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: missing documentation for a function
|
||||
--> $DIR/missing_doc.rs:88:5
|
||||
|
|
||||
LL | fn undocumented3() {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: missing documentation for a function
|
||||
--> $DIR/missing_doc.rs:93:9
|
||||
|
|
||||
LL | pub fn also_undocumented1() {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: missing documentation for a function
|
||||
--> $DIR/missing_doc.rs:94:9
|
||||
|
|
||||
LL | fn also_undocumented2() {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 24 previous errors
|
||||
error: aborting due to 13 previous errors
|
||||
|
||||
|
|
|
@ -21,60 +21,12 @@ error: missing documentation for a struct field
|
|||
LL | b: isize,
|
||||
| ^^^^^^^^
|
||||
|
||||
error: missing documentation for a struct
|
||||
--> $DIR/missing_doc_impl.rs:18:1
|
||||
|
|
||||
LL | / pub struct PubFoo {
|
||||
LL | | pub a: isize,
|
||||
LL | | b: isize,
|
||||
LL | | }
|
||||
| |_^
|
||||
|
||||
error: missing documentation for a struct field
|
||||
--> $DIR/missing_doc_impl.rs:19:5
|
||||
|
|
||||
LL | pub a: isize,
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
error: missing documentation for a struct field
|
||||
--> $DIR/missing_doc_impl.rs:20:5
|
||||
|
|
||||
LL | b: isize,
|
||||
| ^^^^^^^^
|
||||
|
||||
error: missing documentation for a trait
|
||||
--> $DIR/missing_doc_impl.rs:43:1
|
||||
|
|
||||
LL | / pub trait C {
|
||||
LL | | fn foo(&self);
|
||||
LL | | fn foo_with_impl(&self) {}
|
||||
LL | | }
|
||||
| |_^
|
||||
|
||||
error: missing documentation for a method
|
||||
--> $DIR/missing_doc_impl.rs:44:5
|
||||
|
|
||||
LL | fn foo(&self);
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
||||
error: missing documentation for a method
|
||||
--> $DIR/missing_doc_impl.rs:45:5
|
||||
|
|
||||
LL | fn foo_with_impl(&self) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: missing documentation for an associated type
|
||||
--> $DIR/missing_doc_impl.rs:55:5
|
||||
|
|
||||
LL | type AssociatedType;
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: missing documentation for an associated type
|
||||
--> $DIR/missing_doc_impl.rs:56:5
|
||||
|
|
||||
LL | type AssociatedTypeDef = Self;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: missing documentation for an associated function
|
||||
--> $DIR/missing_doc_impl.rs:67:5
|
||||
|
|
||||
|
@ -89,12 +41,6 @@ error: missing documentation for an associated function
|
|||
LL | fn bar() {}
|
||||
| ^^^^^^^^^^^
|
||||
|
||||
error: missing documentation for an associated function
|
||||
--> $DIR/missing_doc_impl.rs:74:5
|
||||
|
|
||||
LL | pub fn foo() {}
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
error: missing documentation for an associated function
|
||||
--> $DIR/missing_doc_impl.rs:78:5
|
||||
|
|
||||
|
@ -103,5 +49,5 @@ LL | | 1
|
|||
LL | | }
|
||||
| |_____^
|
||||
|
||||
error: aborting due to 15 previous errors
|
||||
error: aborting due to 7 previous errors
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue