mirror of
https://github.com/rust-lang/rust-clippy
synced 2024-11-10 07:04:18 +00:00
Merge commit 'cb7915b00c235e9b5861564f3be78dba330980ee' into clippyup
This commit is contained in:
parent
067bfe3618
commit
23d5457e6d
142 changed files with 2227 additions and 1008 deletions
|
@ -1,9 +1,10 @@
|
|||
[alias]
|
||||
uitest = "test --test compile-test"
|
||||
dev = "run --target-dir clippy_dev/target --package clippy_dev --bin clippy_dev --manifest-path clippy_dev/Cargo.toml --"
|
||||
lintcheck = "run --target-dir lintcheck/target --package lintcheck --bin lintcheck --manifest-path lintcheck/Cargo.toml -- "
|
||||
dev = "run --package clippy_dev --bin clippy_dev --manifest-path clippy_dev/Cargo.toml --"
|
||||
lintcheck = "run --package lintcheck --bin lintcheck --manifest-path lintcheck/Cargo.toml -- "
|
||||
collect-metadata = "test --test dogfood --features metadata-collector-lint -- run_metadata_collection_lint --ignored"
|
||||
|
||||
[build]
|
||||
# -Zbinary-dep-depinfo allows us to track which rlib files to use for compiling UI tests
|
||||
rustflags = ["-Zunstable-options", "-Zbinary-dep-depinfo"]
|
||||
target-dir = "target"
|
||||
|
|
2
.github/ISSUE_TEMPLATE/blank_issue.md
vendored
2
.github/ISSUE_TEMPLATE/blank_issue.md
vendored
|
@ -8,7 +8,7 @@ about: Create a blank issue.
|
|||
Additional labels can be added to this issue by including the following command
|
||||
(without the space after the @ symbol):
|
||||
|
||||
`@rustbot label +<label>`
|
||||
@ rustbot label +<label>
|
||||
|
||||
Common labels for this issue type are:
|
||||
* C-an-interesting-project
|
||||
|
|
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
|
@ -36,7 +36,7 @@ LLVM version: 10.0
|
|||
Additional labels can be added to this issue by including the following command
|
||||
(without the space after the @ symbol):
|
||||
|
||||
`@rustbot label +<label>`
|
||||
@ rustbot label +<label>
|
||||
|
||||
Common labels for this issue type are:
|
||||
* `I-suggestion-causes-error`
|
||||
|
|
2
.github/ISSUE_TEMPLATE/false_positive.md
vendored
2
.github/ISSUE_TEMPLATE/false_positive.md
vendored
|
@ -37,7 +37,7 @@ LLVM version: 10.0
|
|||
Additional labels can be added to this issue by including the following command
|
||||
(without the space after the @ symbol):
|
||||
|
||||
`@rustbot label +<label>`
|
||||
@ rustbot label +<label>
|
||||
|
||||
Common labels for this issue type are:
|
||||
* I-suggestion-causes-error
|
||||
|
|
99
CHANGELOG.md
99
CHANGELOG.md
|
@ -6,11 +6,81 @@ document.
|
|||
|
||||
## Unreleased / In Rust Nightly
|
||||
|
||||
[74d1561...master](https://github.com/rust-lang/rust-clippy/compare/74d1561...master)
|
||||
[7bfc26e...master](https://github.com/rust-lang/rust-clippy/compare/7bfc26e...master)
|
||||
|
||||
## Rust 1.56
|
||||
|
||||
Current beta, release 2021-10-21
|
||||
|
||||
[74d1561...7bfc26e](https://github.com/rust-lang/rust-clippy/compare/74d1561...7bfc26e)
|
||||
|
||||
### New Lints
|
||||
|
||||
* [`unwrap_or_else_default`]
|
||||
[#7516](https://github.com/rust-lang/rust-clippy/pull/7516)
|
||||
|
||||
### Enhancements
|
||||
|
||||
* [`needless_continue`]: Now also lints in `loop { continue; }` case
|
||||
[#7477](https://github.com/rust-lang/rust-clippy/pull/7477)
|
||||
* [`disallowed_type`]: Now also primitive types can be disallowed
|
||||
[#7488](https://github.com/rust-lang/rust-clippy/pull/7488)
|
||||
* [`manual_swap`]: Now also lints on xor swaps
|
||||
[#7506](https://github.com/rust-lang/rust-clippy/pull/7506)
|
||||
* [`map_flatten`]: Now also lints on the `Result` type
|
||||
[#7522](https://github.com/rust-lang/rust-clippy/pull/7522)
|
||||
* [`no_effect`]: Now also lints on inclusive ranges
|
||||
[#7556](https://github.com/rust-lang/rust-clippy/pull/7556)
|
||||
|
||||
### False Positive Fixes
|
||||
|
||||
* [`nonstandard_macro_braces`]: No longer lints on similar named nested macros
|
||||
[#7478](https://github.com/rust-lang/rust-clippy/pull/7478)
|
||||
* [`too_many_lines`]: No longer lints in closures to avoid duplicated diagnostics
|
||||
[#7534](https://github.com/rust-lang/rust-clippy/pull/7534)
|
||||
* [`similar_names`]: No longer complains about `iter` and `item` being too
|
||||
similar [#7546](https://github.com/rust-lang/rust-clippy/pull/7546)
|
||||
|
||||
### Suggestion Fixes/Improvements
|
||||
|
||||
* [`similar_names`]: No longer suggests to insert or add an underscore as a fix
|
||||
[#7221](https://github.com/rust-lang/rust-clippy/pull/7221)
|
||||
* [`new_without_default`]: No longer shows the full qualified type path when
|
||||
suggesting adding a `Default` implementation
|
||||
[#7493](https://github.com/rust-lang/rust-clippy/pull/7493)
|
||||
* [`while_let_on_iterator`]: Now suggests re-borrowing mutable references
|
||||
[#7520](https://github.com/rust-lang/rust-clippy/pull/7520)
|
||||
* [`extend_with_drain`]: Improve code suggestion for mutable and immutable
|
||||
references [#7533](https://github.com/rust-lang/rust-clippy/pull/7533)
|
||||
* [`trivially_copy_pass_by_ref`]: Now properly handles `Self` type
|
||||
[#7535](https://github.com/rust-lang/rust-clippy/pull/7535)
|
||||
* [`never_loop`]: Now suggests using `if let` instead of a `for` loop when
|
||||
applicable [#7541](https://github.com/rust-lang/rust-clippy/pull/7541)
|
||||
|
||||
### Documentation Improvements
|
||||
|
||||
* Clippy now uses a lint to generate its lint documentation. [Lints all the way
|
||||
down](https://en.wikipedia.org/wiki/Turtles_all_the_way_down).
|
||||
[#7502](https://github.com/rust-lang/rust-clippy/pull/7502)
|
||||
* Reworked Clippy's website:
|
||||
[#7172](https://github.com/rust-lang/rust-clippy/issues/7172)
|
||||
[#7279](https://github.com/rust-lang/rust-clippy/pull/7279)
|
||||
* Added applicability information about lints
|
||||
* Added a link to jump into the implementation
|
||||
* Improved loading times
|
||||
* Adapted some styling
|
||||
* `cargo clippy --help` now also explains the `--fix` and `--no-deps` flag
|
||||
[#7492](https://github.com/rust-lang/rust-clippy/pull/7492)
|
||||
* [`unnested_or_patterns`]: Removed `or_patterns` feature gate in the code
|
||||
example [#7507](https://github.com/rust-lang/rust-clippy/pull/7507)
|
||||
|
||||
### New Lints
|
||||
|
||||
* Renamed Lint: `if_let_some_result` is now called [`match_result_ok`]. Now also handles `while let` case.
|
||||
|
||||
## Rust 1.55
|
||||
|
||||
Current beta, release 2021-09-09
|
||||
Current stable, released 2021-09-09
|
||||
|
||||
[3ae8faf...74d1561](https://github.com/rust-lang/rust-clippy/compare/3ae8faf...74d1561)
|
||||
|
||||
|
@ -126,21 +196,9 @@ Current beta, release 2021-09-09
|
|||
* [`use_self`]
|
||||
[#7428](https://github.com/rust-lang/rust-clippy/pull/7428)
|
||||
|
||||
### Documentation Improvements
|
||||
|
||||
* Reworked Clippy's website:
|
||||
[#7279](https://github.com/rust-lang/rust-clippy/pull/7279)
|
||||
[#7172](https://github.com/rust-lang/rust-clippy/issues/7172)
|
||||
* Added applicability information about lints
|
||||
* Added a link to jump into the implementation
|
||||
* Improved loading times
|
||||
* Adapted some styling
|
||||
* Clippy now uses a lint to generate its documentation
|
||||
[#7298](https://github.com/rust-lang/rust-clippy/pull/7298)
|
||||
|
||||
## Rust 1.54
|
||||
|
||||
Current stable, released 2021-07-29
|
||||
Released 2021-07-29
|
||||
|
||||
[7c7683c...3ae8faf](https://github.com/rust-lang/rust-clippy/compare/7c7683c...3ae8faf)
|
||||
|
||||
|
@ -1050,7 +1108,7 @@ Released 2020-11-19
|
|||
[#5913](https://github.com/rust-lang/rust-clippy/pull/5913)
|
||||
* Add example of false positive to [`ptr_arg`] docs.
|
||||
[#5885](https://github.com/rust-lang/rust-clippy/pull/5885)
|
||||
* [`box_vec`], [`vec_box`] and [`borrowed_box`]: add link to the documentation of `Box`
|
||||
* [`box_vec`](https://rust-lang.github.io/rust-clippy/master/index.html#box_collection), [`vec_box`] and [`borrowed_box`]: add link to the documentation of `Box`
|
||||
[#6023](https://github.com/rust-lang/rust-clippy/pull/6023)
|
||||
|
||||
## Rust 1.47
|
||||
|
@ -1491,7 +1549,7 @@ Released 2020-03-12
|
|||
* `unknown_clippy_lints` [#4963](https://github.com/rust-lang/rust-clippy/pull/4963)
|
||||
* [`explicit_into_iter_loop`] [#4978](https://github.com/rust-lang/rust-clippy/pull/4978)
|
||||
* [`useless_attribute`] [#5022](https://github.com/rust-lang/rust-clippy/pull/5022)
|
||||
* [`if_let_some_result`] [#5032](https://github.com/rust-lang/rust-clippy/pull/5032)
|
||||
* `if_let_some_result` [#5032](https://github.com/rust-lang/rust-clippy/pull/5032)
|
||||
|
||||
### ICE fixes
|
||||
|
||||
|
@ -2570,7 +2628,7 @@ Released 2018-09-13
|
|||
[`bool_comparison`]: https://rust-lang.github.io/rust-clippy/master/index.html#bool_comparison
|
||||
[`borrow_interior_mutable_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#borrow_interior_mutable_const
|
||||
[`borrowed_box`]: https://rust-lang.github.io/rust-clippy/master/index.html#borrowed_box
|
||||
[`box_vec`]: https://rust-lang.github.io/rust-clippy/master/index.html#box_vec
|
||||
[`box_collection`]: https://rust-lang.github.io/rust-clippy/master/index.html#box_collection
|
||||
[`boxed_local`]: https://rust-lang.github.io/rust-clippy/master/index.html#boxed_local
|
||||
[`branches_sharing_code`]: https://rust-lang.github.io/rust-clippy/master/index.html#branches_sharing_code
|
||||
[`builtin_type_shadow`]: https://rust-lang.github.io/rust-clippy/master/index.html#builtin_type_shadow
|
||||
|
@ -2685,9 +2743,9 @@ Released 2018-09-13
|
|||
[`identity_op`]: https://rust-lang.github.io/rust-clippy/master/index.html#identity_op
|
||||
[`if_let_mutex`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_let_mutex
|
||||
[`if_let_redundant_pattern_matching`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_let_redundant_pattern_matching
|
||||
[`if_let_some_result`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_let_some_result
|
||||
[`if_not_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_not_else
|
||||
[`if_same_then_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_same_then_else
|
||||
[`if_then_panic`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_then_panic
|
||||
[`if_then_some_else_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_then_some_else_none
|
||||
[`ifs_same_cond`]: https://rust-lang.github.io/rust-clippy/master/index.html#ifs_same_cond
|
||||
[`implicit_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_clone
|
||||
|
@ -2722,6 +2780,7 @@ Released 2018-09-13
|
|||
[`iter_count`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_count
|
||||
[`iter_next_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_next_loop
|
||||
[`iter_next_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_next_slice
|
||||
[`iter_not_returning_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_not_returning_iterator
|
||||
[`iter_nth`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_nth
|
||||
[`iter_nth_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_nth_zero
|
||||
[`iter_skip_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_skip_next
|
||||
|
@ -2773,6 +2832,7 @@ Released 2018-09-13
|
|||
[`match_on_vec_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_on_vec_items
|
||||
[`match_overlapping_arm`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_overlapping_arm
|
||||
[`match_ref_pats`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_ref_pats
|
||||
[`match_result_ok`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_result_ok
|
||||
[`match_same_arms`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_same_arms
|
||||
[`match_single_binding`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_single_binding
|
||||
[`match_wild_err_arm`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_wild_err_arm
|
||||
|
@ -2905,6 +2965,7 @@ Released 2018-09-13
|
|||
[`reversed_empty_ranges`]: https://rust-lang.github.io/rust-clippy/master/index.html#reversed_empty_ranges
|
||||
[`same_functions_in_if_condition`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_functions_in_if_condition
|
||||
[`same_item_push`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_item_push
|
||||
[`same_name_method`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_name_method
|
||||
[`search_is_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#search_is_some
|
||||
[`self_assignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#self_assignment
|
||||
[`self_named_constructors`]: https://rust-lang.github.io/rust-clippy/master/index.html#self_named_constructors
|
||||
|
|
|
@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
|
|||
keywords = ["clippy", "lint", "plugin"]
|
||||
categories = ["development-tools", "development-tools::cargo-plugins"]
|
||||
build = "build.rs"
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
|
||||
[[bin]]
|
||||
|
|
|
@ -18,7 +18,7 @@ You can choose how much Clippy is supposed to ~~annoy~~ help you by changing the
|
|||
| `clippy::style` | code that should be written in a more idiomatic way | **warn** |
|
||||
| `clippy::complexity` | code that does something simple but in a complex way | **warn** |
|
||||
| `clippy::perf` | code that can be written to run faster | **warn** |
|
||||
| `clippy::pedantic` | lints which are rather strict or might have false positives | allow |
|
||||
| `clippy::pedantic` | lints which are rather strict or have occasional false positives | allow |
|
||||
| `clippy::nursery` | new lints that are still under development | allow |
|
||||
| `clippy::cargo` | lints for the cargo manifest | allow |
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
[package]
|
||||
name = "clippy_dev"
|
||||
version = "0.0.1"
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
bytecount = "0.6"
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
//! `bless` updates the reference files in the repo with changed output files
|
||||
//! from the last test run.
|
||||
|
||||
use std::env;
|
||||
use std::ffi::OsStr;
|
||||
use std::fs;
|
||||
use std::lazy::SyncLazy;
|
||||
|
@ -10,17 +9,9 @@ use walkdir::WalkDir;
|
|||
|
||||
use crate::clippy_project_root;
|
||||
|
||||
// NOTE: this is duplicated with tests/cargo/mod.rs What to do?
|
||||
pub static CARGO_TARGET_DIR: SyncLazy<PathBuf> = SyncLazy::new(|| match env::var_os("CARGO_TARGET_DIR") {
|
||||
Some(v) => v.into(),
|
||||
None => env::current_dir().unwrap().join("target"),
|
||||
});
|
||||
|
||||
static CLIPPY_BUILD_TIME: SyncLazy<Option<std::time::SystemTime>> = SyncLazy::new(|| {
|
||||
let profile = env::var("PROFILE").unwrap_or_else(|_| "debug".to_string());
|
||||
let mut path = PathBuf::from(&**CARGO_TARGET_DIR);
|
||||
path.push(profile);
|
||||
path.push("cargo-clippy");
|
||||
let mut path = std::env::current_exe().unwrap();
|
||||
path.set_file_name("cargo-clippy");
|
||||
fs::metadata(path).ok()?.modified().ok()
|
||||
});
|
||||
|
||||
|
@ -94,10 +85,7 @@ fn updated_since_clippy_build(path: &Path) -> Option<bool> {
|
|||
}
|
||||
|
||||
fn build_dir() -> PathBuf {
|
||||
let profile = env::var("PROFILE").unwrap_or_else(|_| "debug".to_string());
|
||||
let mut path = PathBuf::new();
|
||||
path.push(CARGO_TARGET_DIR.clone());
|
||||
path.push(profile);
|
||||
path.push("test_build_base");
|
||||
let mut path = std::env::current_exe().unwrap();
|
||||
path.set_file_name("test");
|
||||
path
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ repository = "https://github.com/rust-lang/rust-clippy"
|
|||
readme = "README.md"
|
||||
license = "MIT OR Apache-2.0"
|
||||
keywords = ["clippy", "lint", "plugin"]
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
cargo_metadata = "0.12"
|
||||
|
|
|
@ -2,10 +2,9 @@ use clippy_utils::diagnostics::span_lint_and_help;
|
|||
use clippy_utils::{in_macro, is_automatically_derived, is_default_equivalent, remove_blocks};
|
||||
use rustc_hir::{
|
||||
def::{DefKind, Res},
|
||||
Body, Expr, ExprKind, Impl, ImplItemKind, Item, ItemKind, Node, QPath,
|
||||
Body, Expr, ExprKind, GenericArg, Impl, ImplItemKind, Item, ItemKind, Node, PathSegment, QPath, TyKind,
|
||||
};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty::TypeFoldable;
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::sym;
|
||||
|
||||
|
@ -68,6 +67,7 @@ impl<'tcx> LateLintPass<'tcx> for DerivableImpls {
|
|||
if let ItemKind::Impl(Impl {
|
||||
of_trait: Some(ref trait_ref),
|
||||
items: [child],
|
||||
self_ty,
|
||||
..
|
||||
}) = item.kind;
|
||||
if let attrs = cx.tcx.hir().attrs(item.hir_id());
|
||||
|
@ -80,9 +80,18 @@ impl<'tcx> LateLintPass<'tcx> for DerivableImpls {
|
|||
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.def_id).ty_adt_def();
|
||||
if !attrs.iter().any(|attr| attr.doc_str().is_some());
|
||||
if let child_attrs = cx.tcx.hir().attrs(impl_item_hir);
|
||||
if !child_attrs.iter().any(|attr| attr.doc_str().is_some());
|
||||
then {
|
||||
if cx.tcx.type_of(item.def_id).definitely_has_param_types_or_consts(cx.tcx) {
|
||||
return;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let should_emit = match remove_blocks(func_expr).kind {
|
||||
ExprKind::Tup(fields) => fields.iter().all(|e| is_default_equivalent(cx, e)),
|
||||
|
|
|
@ -1,33 +1,44 @@
|
|||
use clippy_utils::diagnostics::span_lint;
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::fn_def_id;
|
||||
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_hir::{def::Res, def_id::DefId, Crate, Expr};
|
||||
use rustc_hir::{def::Res, def_id::DefIdMap, Crate, Expr};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_span::Symbol;
|
||||
|
||||
use crate::utils::conf;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Denies the configured methods and functions in clippy.toml
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// Some methods are undesirable in certain contexts,
|
||||
/// and it's beneficial to lint for them as needed.
|
||||
/// Some methods are undesirable in certain contexts, and it's beneficial to
|
||||
/// lint for them as needed.
|
||||
///
|
||||
/// ### Example
|
||||
/// An example clippy.toml configuration:
|
||||
/// ```toml
|
||||
/// # clippy.toml
|
||||
/// disallowed-methods = ["std::vec::Vec::leak", "std::time::Instant::now"]
|
||||
/// disallowed-methods = [
|
||||
/// # Can use a string as the path of the disallowed method.
|
||||
/// "std::boxed::Box::new",
|
||||
/// # Can also use an inline table with a `path` key.
|
||||
/// { path = "std::time::Instant::now" },
|
||||
/// # When using an inline table, can add a `reason` for why the method
|
||||
/// # is disallowed.
|
||||
/// { path = "std::vec::Vec::leak", reason = "no leaking memory" },
|
||||
/// ]
|
||||
/// ```
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// // Example code where clippy issues a warning
|
||||
/// let xs = vec![1, 2, 3, 4];
|
||||
/// xs.leak(); // Vec::leak is disallowed in the config.
|
||||
/// // The diagnostic contains the message "no leaking memory".
|
||||
///
|
||||
/// let _now = Instant::now(); // Instant::now is disallowed in the config.
|
||||
///
|
||||
/// let _box = Box::new(3); // Box::new is disallowed in the config.
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
|
@ -43,18 +54,15 @@ declare_clippy_lint! {
|
|||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct DisallowedMethod {
|
||||
disallowed: FxHashSet<Vec<Symbol>>,
|
||||
def_ids: FxHashSet<(DefId, Vec<Symbol>)>,
|
||||
conf_disallowed: Vec<conf::DisallowedMethod>,
|
||||
disallowed: DefIdMap<Option<String>>,
|
||||
}
|
||||
|
||||
impl DisallowedMethod {
|
||||
pub fn new(disallowed: &FxHashSet<String>) -> Self {
|
||||
pub fn new(conf_disallowed: Vec<conf::DisallowedMethod>) -> Self {
|
||||
Self {
|
||||
disallowed: disallowed
|
||||
.iter()
|
||||
.map(|s| s.split("::").map(|seg| Symbol::intern(seg)).collect::<Vec<_>>())
|
||||
.collect(),
|
||||
def_ids: FxHashSet::default(),
|
||||
conf_disallowed,
|
||||
disallowed: DefIdMap::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -63,32 +71,36 @@ impl_lint_pass!(DisallowedMethod => [DISALLOWED_METHOD]);
|
|||
|
||||
impl<'tcx> LateLintPass<'tcx> for DisallowedMethod {
|
||||
fn check_crate(&mut self, cx: &LateContext<'_>, _: &Crate<'_>) {
|
||||
for path in &self.disallowed {
|
||||
let segs = path.iter().map(ToString::to_string).collect::<Vec<_>>();
|
||||
if let Res::Def(_, id) = clippy_utils::path_to_res(cx, &segs.iter().map(String::as_str).collect::<Vec<_>>())
|
||||
{
|
||||
self.def_ids.insert((id, path.clone()));
|
||||
for conf in &self.conf_disallowed {
|
||||
let (path, reason) = match conf {
|
||||
conf::DisallowedMethod::Simple(path) => (path, None),
|
||||
conf::DisallowedMethod::WithReason { path, reason } => (
|
||||
path,
|
||||
reason.as_ref().map(|reason| format!("{} (from clippy.toml)", reason)),
|
||||
),
|
||||
};
|
||||
let segs: Vec<_> = path.split("::").collect();
|
||||
if let Res::Def(_, id) = clippy_utils::path_to_res(cx, &segs) {
|
||||
self.disallowed.insert(id, reason);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
if let Some(def_id) = fn_def_id(cx, expr) {
|
||||
if self.def_ids.iter().any(|(id, _)| def_id == *id) {
|
||||
let func_path = cx.get_def_path(def_id);
|
||||
let func_path_string = func_path
|
||||
.into_iter()
|
||||
.map(Symbol::to_ident_string)
|
||||
.collect::<Vec<_>>()
|
||||
.join("::");
|
||||
|
||||
span_lint(
|
||||
cx,
|
||||
DISALLOWED_METHOD,
|
||||
expr.span,
|
||||
&format!("use of a disallowed method `{}`", func_path_string),
|
||||
);
|
||||
let def_id = match fn_def_id(cx, expr) {
|
||||
Some(def_id) => def_id,
|
||||
None => return,
|
||||
};
|
||||
let reason = match self.disallowed.get(&def_id) {
|
||||
Some(reason) => reason,
|
||||
None => return,
|
||||
};
|
||||
let func_path = cx.tcx.def_path_str(def_id);
|
||||
let msg = format!("use of a disallowed method `{}`", func_path);
|
||||
span_lint_and_then(cx, DISALLOWED_METHOD, expr.span, &msg, |diag| {
|
||||
if let Some(reason) = reason {
|
||||
diag.note(reason);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ impl DisallowedType {
|
|||
Self {
|
||||
disallowed: disallowed
|
||||
.iter()
|
||||
.map(|s| s.split("::").map(|seg| Symbol::intern(seg)).collect::<Vec<_>>())
|
||||
.map(|s| s.split("::").map(Symbol::intern).collect::<Vec<_>>())
|
||||
.collect(),
|
||||
def_ids: FxHashSet::default(),
|
||||
prim_tys: FxHashSet::default(),
|
||||
|
|
|
@ -91,8 +91,11 @@ impl<'tcx> LateLintPass<'tcx> for BoxedLocal {
|
|||
if trait_item.id.hir_id() == hir_id {
|
||||
// be sure we have `self` parameter in this function
|
||||
if let AssocItemKind::Fn { has_self: true } = trait_item.kind {
|
||||
trait_self_ty =
|
||||
Some(TraitRef::identity(cx.tcx, trait_item.id.def_id.to_def_id()).self_ty().skip_binder());
|
||||
trait_self_ty = Some(
|
||||
TraitRef::identity(cx.tcx, trait_item.id.def_id.to_def_id())
|
||||
.self_ty()
|
||||
.skip_binder(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
|
||||
use clippy_utils::higher::VecArgs;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::ty::{implements_trait, type_is_unsafe_function};
|
||||
use clippy_utils::usage::UsedAfterExprVisitor;
|
||||
use clippy_utils::{get_enclosing_loop_or_closure, higher};
|
||||
use clippy_utils::{is_adjusted, iter_input_pats};
|
||||
use clippy_utils::{get_enclosing_loop_or_closure, higher, path_to_local_id};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{def_id, Expr, ExprKind, Param, PatKind, QPath};
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_middle::ty::{self, ClosureKind, Ty};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::{Expr, ExprKind, Param, PatKind, Unsafety};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
|
||||
use rustc_middle::ty::subst::Subst;
|
||||
use rustc_middle::ty::{self, ClosureKind, Ty, TypeFoldable};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
|
||||
declare_clippy_lint! {
|
||||
|
@ -52,12 +52,6 @@ declare_clippy_lint! {
|
|||
/// ### Why is this bad?
|
||||
/// It's unnecessary to create the closure.
|
||||
///
|
||||
/// ### Known problems
|
||||
/// [#3071](https://github.com/rust-lang/rust-clippy/issues/3071),
|
||||
/// [#3942](https://github.com/rust-lang/rust-clippy/issues/3942),
|
||||
/// [#4002](https://github.com/rust-lang/rust-clippy/issues/4002)
|
||||
///
|
||||
///
|
||||
/// ### Example
|
||||
/// ```rust,ignore
|
||||
/// Some('a').map(|s| s.to_uppercase());
|
||||
|
@ -75,32 +69,16 @@ declare_lint_pass!(EtaReduction => [REDUNDANT_CLOSURE, REDUNDANT_CLOSURE_FOR_MET
|
|||
|
||||
impl<'tcx> LateLintPass<'tcx> for EtaReduction {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
if in_external_macro(cx.sess(), expr.span) {
|
||||
if expr.span.from_expansion() {
|
||||
return;
|
||||
}
|
||||
|
||||
match expr.kind {
|
||||
ExprKind::Call(_, args) | ExprKind::MethodCall(_, _, args, _) => {
|
||||
for arg in args {
|
||||
// skip `foo(macro!())`
|
||||
if arg.span.ctxt() == expr.span.ctxt() {
|
||||
check_closure(cx, arg);
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_closure<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
if let ExprKind::Closure(_, decl, eid, _, _) = expr.kind {
|
||||
let body = cx.tcx.hir().body(eid);
|
||||
let ex = &body.value;
|
||||
|
||||
if ex.span.ctxt() != expr.span.ctxt() {
|
||||
if decl.inputs.is_empty() {
|
||||
if let Some(VecArgs::Vec(&[])) = higher::VecArgs::hir(cx, ex) {
|
||||
let body = match expr.kind {
|
||||
ExprKind::Closure(_, _, id, _, _) => cx.tcx.hir().body(id),
|
||||
_ => return,
|
||||
};
|
||||
if body.value.span.from_expansion() {
|
||||
if body.params.is_empty() {
|
||||
if let Some(VecArgs::Vec(&[])) = higher::VecArgs::hir(cx, &body.value) {
|
||||
// replace `|| vec![]` with `Vec::new`
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
|
@ -117,33 +95,30 @@ fn check_closure<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
|||
return;
|
||||
}
|
||||
|
||||
let closure_ty = cx.typeck_results().expr_ty(expr);
|
||||
|
||||
if_chain!(
|
||||
if let ExprKind::Call(caller, args) = ex.kind;
|
||||
|
||||
if let ExprKind::Path(_) = caller.kind;
|
||||
|
||||
// Not the same number of arguments, there is no way the closure is the same as the function return;
|
||||
if args.len() == decl.inputs.len();
|
||||
|
||||
// Are the expression or the arguments type-adjusted? Then we need the closure
|
||||
if !(is_adjusted(cx, ex) || args.iter().any(|arg| is_adjusted(cx, arg)));
|
||||
|
||||
let fn_ty = cx.typeck_results().expr_ty(caller);
|
||||
|
||||
if matches!(fn_ty.kind(), ty::FnDef(_, _) | ty::FnPtr(_) | ty::Closure(_, _));
|
||||
|
||||
if !type_is_unsafe_function(cx, fn_ty);
|
||||
|
||||
if compare_inputs(&mut iter_input_pats(decl, body), &mut args.iter());
|
||||
|
||||
if let ExprKind::Call(callee, args) = body.value.kind;
|
||||
if let ExprKind::Path(_) = callee.kind;
|
||||
if check_inputs(cx, body.params, args);
|
||||
let callee_ty = cx.typeck_results().expr_ty_adjusted(callee);
|
||||
let call_ty = cx.typeck_results().type_dependent_def_id(body.value.hir_id)
|
||||
.map_or(callee_ty, |id| cx.tcx.type_of(id));
|
||||
if check_sig(cx, closure_ty, call_ty);
|
||||
let substs = cx.typeck_results().node_substs(callee.hir_id);
|
||||
// This fixes some false positives that I don't entirely understand
|
||||
if substs.is_empty() || !cx.typeck_results().expr_ty(expr).has_late_bound_regions();
|
||||
// A type param function ref like `T::f` is not 'static, however
|
||||
// it is if cast like `T::f as fn()`. This seems like a rustc bug.
|
||||
if !substs.types().any(|t| matches!(t.kind(), ty::Param(_)));
|
||||
then {
|
||||
span_lint_and_then(cx, REDUNDANT_CLOSURE, expr.span, "redundant closure", |diag| {
|
||||
if let Some(mut snippet) = snippet_opt(cx, caller.span) {
|
||||
if let Some(mut snippet) = snippet_opt(cx, callee.span) {
|
||||
if_chain! {
|
||||
if let ty::Closure(_, substs) = fn_ty.kind();
|
||||
if let ty::Closure(_, substs) = callee_ty.peel_refs().kind();
|
||||
if let ClosureKind::FnMut = substs.as_closure().kind();
|
||||
if UsedAfterExprVisitor::is_found(cx, caller)
|
||||
|| get_enclosing_loop_or_closure(cx.tcx, expr).is_some();
|
||||
if get_enclosing_loop_or_closure(cx.tcx, expr).is_some()
|
||||
|| UsedAfterExprVisitor::is_found(cx, callee);
|
||||
|
||||
then {
|
||||
// Mutable closure is used after current expr; we cannot consume it.
|
||||
|
@ -162,110 +137,79 @@ fn check_closure<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
|||
);
|
||||
|
||||
if_chain!(
|
||||
if let ExprKind::MethodCall(path, _, args, _) = ex.kind;
|
||||
|
||||
// Not the same number of arguments, there is no way the closure is the same as the function return;
|
||||
if args.len() == decl.inputs.len();
|
||||
|
||||
// Are the expression or the arguments type-adjusted? Then we need the closure
|
||||
if !(is_adjusted(cx, ex) || args.iter().skip(1).any(|arg| is_adjusted(cx, arg)));
|
||||
|
||||
let method_def_id = cx.typeck_results().type_dependent_def_id(ex.hir_id).unwrap();
|
||||
if !type_is_unsafe_function(cx, cx.tcx.type_of(method_def_id));
|
||||
|
||||
if compare_inputs(&mut iter_input_pats(decl, body), &mut args.iter());
|
||||
|
||||
if let Some(name) = get_ufcs_type_name(cx, method_def_id, &args[0]);
|
||||
|
||||
if let ExprKind::MethodCall(path, _, args, _) = body.value.kind;
|
||||
if check_inputs(cx, body.params, args);
|
||||
let method_def_id = cx.typeck_results().type_dependent_def_id(body.value.hir_id).unwrap();
|
||||
let substs = cx.typeck_results().node_substs(body.value.hir_id);
|
||||
let call_ty = cx.tcx.type_of(method_def_id).subst(cx.tcx, substs);
|
||||
if check_sig(cx, closure_ty, call_ty);
|
||||
then {
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
REDUNDANT_CLOSURE_FOR_METHOD_CALLS,
|
||||
expr.span,
|
||||
"redundant closure",
|
||||
"replace the closure with the method itself",
|
||||
format!("{}::{}", name, path.ident.name),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
span_lint_and_then(cx, REDUNDANT_CLOSURE_FOR_METHOD_CALLS, expr.span, "redundant closure", |diag| {
|
||||
let name = get_ufcs_type_name(cx, method_def_id);
|
||||
diag.span_suggestion(
|
||||
expr.span,
|
||||
"replace the closure with the method itself",
|
||||
format!("{}::{}", name, path.ident.name),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
})
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Tries to determine the type for universal function call to be used instead of the closure
|
||||
fn get_ufcs_type_name(cx: &LateContext<'_>, method_def_id: def_id::DefId, self_arg: &Expr<'_>) -> Option<String> {
|
||||
let expected_type_of_self = &cx.tcx.fn_sig(method_def_id).inputs_and_output().skip_binder()[0];
|
||||
let actual_type_of_self = &cx.typeck_results().node_type(self_arg.hir_id);
|
||||
|
||||
if let Some(trait_id) = cx.tcx.trait_of_item(method_def_id) {
|
||||
if match_borrow_depth(expected_type_of_self, actual_type_of_self)
|
||||
&& implements_trait(cx, actual_type_of_self, trait_id, &[])
|
||||
{
|
||||
return Some(cx.tcx.def_path_str(trait_id));
|
||||
}
|
||||
fn check_inputs(cx: &LateContext<'_>, params: &[Param<'_>], call_args: &[Expr<'_>]) -> bool {
|
||||
if params.len() != call_args.len() {
|
||||
return false;
|
||||
}
|
||||
|
||||
cx.tcx.impl_of_method(method_def_id).and_then(|_| {
|
||||
//a type may implicitly implement other type's methods (e.g. Deref)
|
||||
if match_types(expected_type_of_self, actual_type_of_self) {
|
||||
Some(get_type_name(cx, actual_type_of_self))
|
||||
} else {
|
||||
None
|
||||
std::iter::zip(params, call_args).all(|(param, arg)| {
|
||||
match param.pat.kind {
|
||||
PatKind::Binding(_, id, ..) if path_to_local_id(arg, id) => {},
|
||||
_ => return false,
|
||||
}
|
||||
match *cx.typeck_results().expr_adjustments(arg) {
|
||||
[] => true,
|
||||
[Adjustment {
|
||||
kind: Adjust::Deref(None),
|
||||
..
|
||||
}, Adjustment {
|
||||
kind: Adjust::Borrow(AutoBorrow::Ref(_, mu2)),
|
||||
..
|
||||
}] => {
|
||||
// re-borrow with the same mutability is allowed
|
||||
let ty = cx.typeck_results().expr_ty(arg);
|
||||
matches!(*ty.kind(), ty::Ref(.., mu1) if mu1 == mu2.into())
|
||||
},
|
||||
_ => false,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn match_borrow_depth(lhs: Ty<'_>, rhs: Ty<'_>) -> bool {
|
||||
match (&lhs.kind(), &rhs.kind()) {
|
||||
(ty::Ref(_, t1, mut1), ty::Ref(_, t2, mut2)) => mut1 == mut2 && match_borrow_depth(t1, t2),
|
||||
(l, r) => !matches!((l, r), (ty::Ref(_, _, _), _) | (_, ty::Ref(_, _, _))),
|
||||
fn check_sig<'tcx>(cx: &LateContext<'tcx>, closure_ty: Ty<'tcx>, call_ty: Ty<'tcx>) -> bool {
|
||||
let call_sig = call_ty.fn_sig(cx.tcx);
|
||||
if call_sig.unsafety() == Unsafety::Unsafe {
|
||||
return false;
|
||||
}
|
||||
if !closure_ty.has_late_bound_regions() {
|
||||
return true;
|
||||
}
|
||||
let substs = match closure_ty.kind() {
|
||||
ty::Closure(_, substs) => substs,
|
||||
_ => return false,
|
||||
};
|
||||
let closure_sig = cx.tcx.signature_unclosure(substs.as_closure().sig(), Unsafety::Normal);
|
||||
cx.tcx.erase_late_bound_regions(closure_sig) == cx.tcx.erase_late_bound_regions(call_sig)
|
||||
}
|
||||
|
||||
fn match_types(lhs: Ty<'_>, rhs: Ty<'_>) -> bool {
|
||||
match (&lhs.kind(), &rhs.kind()) {
|
||||
(ty::Bool, ty::Bool)
|
||||
| (ty::Char, ty::Char)
|
||||
| (ty::Int(_), ty::Int(_))
|
||||
| (ty::Uint(_), ty::Uint(_))
|
||||
| (ty::Str, ty::Str) => true,
|
||||
(ty::Ref(_, t1, mut1), ty::Ref(_, t2, mut2)) => mut1 == mut2 && match_types(t1, t2),
|
||||
(ty::Array(t1, _), ty::Array(t2, _)) | (ty::Slice(t1), ty::Slice(t2)) => match_types(t1, t2),
|
||||
(ty::Adt(def1, _), ty::Adt(def2, _)) => def1 == def2,
|
||||
(_, _) => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_type_name(cx: &LateContext<'_>, ty: Ty<'_>) -> String {
|
||||
match ty.kind() {
|
||||
ty::Adt(t, _) => cx.tcx.def_path_str(t.did),
|
||||
ty::Ref(_, r, _) => get_type_name(cx, r),
|
||||
_ => ty.to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
fn compare_inputs(
|
||||
closure_inputs: &mut dyn Iterator<Item = &Param<'_>>,
|
||||
call_args: &mut dyn Iterator<Item = &Expr<'_>>,
|
||||
) -> bool {
|
||||
for (closure_input, function_arg) in closure_inputs.zip(call_args) {
|
||||
if let PatKind::Binding(_, _, ident, _) = closure_input.pat.kind {
|
||||
// XXXManishearth Should I be checking the binding mode here?
|
||||
if let ExprKind::Path(QPath::Resolved(None, p)) = function_arg.kind {
|
||||
if p.segments.len() != 1 {
|
||||
// If it's a proper path, it can't be a local variable
|
||||
return false;
|
||||
}
|
||||
if p.segments[0].ident.name != ident.name {
|
||||
// The two idents should be the same
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
fn get_ufcs_type_name(cx: &LateContext<'_>, method_def_id: DefId) -> String {
|
||||
match cx.tcx.associated_item(method_def_id).container {
|
||||
ty::TraitContainer(def_id) => cx.tcx.def_path_str(def_id),
|
||||
ty::ImplContainer(def_id) => {
|
||||
let ty = cx.tcx.type_of(def_id);
|
||||
match ty.kind() {
|
||||
ty::Adt(adt, _) => cx.tcx.def_path_str(adt.did),
|
||||
_ => ty.to_string(),
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
}
|
||||
true
|
||||
}
|
||||
|
|
|
@ -111,7 +111,7 @@ impl<'tcx> LateLintPass<'tcx> for FloatLiteral {
|
|||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
} else if digits > max as usize && sym_str != float_str {
|
||||
} else if digits > max as usize && float_str.len() < sym_str.len() {
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
EXCESSIVE_PRECISION,
|
||||
|
|
|
@ -69,8 +69,8 @@ impl<'tcx> LateLintPass<'tcx> for UselessFormat {
|
|||
ty::Str => true,
|
||||
_ => false,
|
||||
};
|
||||
if format_args.args.iter().all(|e| is_display_arg(e));
|
||||
if format_args.fmt_expr.map_or(true, |e| check_unformatted(e));
|
||||
if format_args.args.iter().all(is_display_arg);
|
||||
if format_args.fmt_expr.map_or(true, check_unformatted);
|
||||
then {
|
||||
let is_new_string = match value.kind {
|
||||
ExprKind::Binary(..) => true,
|
||||
|
|
|
@ -286,34 +286,39 @@ fn check_array(cx: &EarlyContext<'_>, expr: &Expr) {
|
|||
}
|
||||
|
||||
fn check_missing_else(cx: &EarlyContext<'_>, first: &Expr, second: &Expr) {
|
||||
if !differing_macro_contexts(first.span, second.span)
|
||||
&& !first.span.from_expansion()
|
||||
&& is_if(first)
|
||||
&& (is_block(second) || is_if(second))
|
||||
{
|
||||
// where the else would be
|
||||
if_chain! {
|
||||
if !differing_macro_contexts(first.span, second.span);
|
||||
if !first.span.from_expansion();
|
||||
if let ExprKind::If(cond_expr, ..) = &first.kind;
|
||||
if is_block(second) || is_if(second);
|
||||
|
||||
// Proc-macros can give weird spans. Make sure this is actually an `if`.
|
||||
if let Some(if_snip) = snippet_opt(cx, first.span.until(cond_expr.span));
|
||||
if if_snip.starts_with("if");
|
||||
|
||||
// If there is a line break between the two expressions, don't lint.
|
||||
// If there is a non-whitespace character, this span came from a proc-macro.
|
||||
let else_span = first.span.between(second.span);
|
||||
if let Some(else_snippet) = snippet_opt(cx, else_span);
|
||||
if !else_snippet.chars().any(|c| c == '\n' || !c.is_whitespace());
|
||||
then {
|
||||
let (looks_like, next_thing) = if is_if(second) {
|
||||
("an `else if`", "the second `if`")
|
||||
} else {
|
||||
("an `else {..}`", "the next block")
|
||||
};
|
||||
|
||||
if let Some(else_snippet) = snippet_opt(cx, else_span) {
|
||||
if !else_snippet.contains('\n') {
|
||||
let (looks_like, next_thing) = if is_if(second) {
|
||||
("an `else if`", "the second `if`")
|
||||
} else {
|
||||
("an `else {..}`", "the next block")
|
||||
};
|
||||
|
||||
span_lint_and_note(
|
||||
cx,
|
||||
SUSPICIOUS_ELSE_FORMATTING,
|
||||
else_span,
|
||||
&format!("this looks like {} but the `else` is missing", looks_like),
|
||||
None,
|
||||
&format!(
|
||||
"to remove this lint, add the missing `else` or add a new line before {}",
|
||||
next_thing,
|
||||
),
|
||||
);
|
||||
}
|
||||
span_lint_and_note(
|
||||
cx,
|
||||
SUSPICIOUS_ELSE_FORMATTING,
|
||||
else_span,
|
||||
&format!("this looks like {} but the `else` is missing", looks_like),
|
||||
None,
|
||||
&format!(
|
||||
"to remove this lint, add the missing `else` or add a new line before {}",
|
||||
next_thing,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
97
clippy_lints/src/if_then_panic.rs
Normal file
97
clippy_lints/src/if_then_panic.rs
Normal file
|
@ -0,0 +1,97 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::higher::PanicExpn;
|
||||
use clippy_utils::is_expn_of;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Block, Expr, ExprKind, StmtKind, UnOp};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Detects `if`-then-`panic!` that can be replaced with `assert!`.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// `assert!` is simpler than `if`-then-`panic!`.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```rust
|
||||
/// let sad_people: Vec<&str> = vec![];
|
||||
/// if !sad_people.is_empty() {
|
||||
/// panic!("there are sad people: {:?}", sad_people);
|
||||
/// }
|
||||
/// ```
|
||||
/// Use instead:
|
||||
/// ```rust
|
||||
/// let sad_people: Vec<&str> = vec![];
|
||||
/// assert!(sad_people.is_empty(), "there are sad people: {:?}", sad_people);
|
||||
/// ```
|
||||
pub IF_THEN_PANIC,
|
||||
style,
|
||||
"`panic!` and only a `panic!` in `if`-then statement"
|
||||
}
|
||||
|
||||
declare_lint_pass!(IfThenPanic => [IF_THEN_PANIC]);
|
||||
|
||||
impl LateLintPass<'_> for IfThenPanic {
|
||||
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||
if_chain! {
|
||||
if let Expr {
|
||||
kind: ExprKind:: If(cond, Expr {
|
||||
kind: ExprKind::Block(
|
||||
Block {
|
||||
stmts: [stmt],
|
||||
..
|
||||
},
|
||||
_),
|
||||
..
|
||||
}, None),
|
||||
..
|
||||
} = &expr;
|
||||
if is_expn_of(stmt.span, "panic").is_some();
|
||||
if !matches!(cond.kind, ExprKind::Let(_, _, _));
|
||||
if let StmtKind::Semi(semi) = stmt.kind;
|
||||
if !cx.tcx.sess.source_map().is_multiline(cond.span);
|
||||
|
||||
then {
|
||||
let span = if let Some(panic_expn) = PanicExpn::parse(semi) {
|
||||
match *panic_expn.format_args.value_args {
|
||||
[] => panic_expn.format_args.format_string_span,
|
||||
[.., last] => panic_expn.format_args.format_string_span.to(last.span),
|
||||
}
|
||||
} else {
|
||||
if_chain! {
|
||||
if let ExprKind::Block(block, _) = semi.kind;
|
||||
if let Some(init) = block.expr;
|
||||
if let ExprKind::Call(_, [format_args]) = init.kind;
|
||||
|
||||
then {
|
||||
format_args.span
|
||||
} else {
|
||||
return
|
||||
}
|
||||
}
|
||||
};
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let sugg = snippet_with_applicability(cx, span, "..", &mut applicability);
|
||||
|
||||
let cond_sugg =
|
||||
if let ExprKind::DropTemps(Expr{kind: ExprKind::Unary(UnOp::Not, not_expr), ..}) = cond.kind {
|
||||
snippet_with_applicability(cx, not_expr.span, "..", &mut applicability).to_string()
|
||||
} else {
|
||||
format!("!{}", snippet_with_applicability(cx, cond.span, "..", &mut applicability))
|
||||
};
|
||||
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
IF_THEN_PANIC,
|
||||
expr.span,
|
||||
"only a `panic!` in `if`-then statement",
|
||||
"try",
|
||||
format!("assert!({}, {});", cond_sugg, sugg),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
64
clippy_lints/src/iter_not_returning_iterator.rs
Normal file
64
clippy_lints/src/iter_not_returning_iterator.rs
Normal file
|
@ -0,0 +1,64 @@
|
|||
use clippy_utils::{diagnostics::span_lint, return_ty, ty::implements_trait};
|
||||
use rustc_hir::{ImplItem, ImplItemKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::symbol::kw;
|
||||
use rustc_span::symbol::sym;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Detects methods named `iter` or `iter_mut` that do not have a return type that implements `Iterator`.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// Methods named `iter` or `iter_mut` conventionally return an `Iterator`.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```rust
|
||||
/// // `String` does not implement `Iterator`
|
||||
/// struct Data {}
|
||||
/// impl Data {
|
||||
/// fn iter(&self) -> String {
|
||||
/// todo!()
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
/// Use instead:
|
||||
/// ```rust
|
||||
/// use std::str::Chars;
|
||||
/// struct Data {}
|
||||
/// impl Data {
|
||||
/// fn iter(&self) -> Chars<'static> {
|
||||
/// todo!()
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
pub ITER_NOT_RETURNING_ITERATOR,
|
||||
pedantic,
|
||||
"methods named `iter` or `iter_mut` that do not return an `Iterator`"
|
||||
}
|
||||
|
||||
declare_lint_pass!(IterNotReturningIterator => [ITER_NOT_RETURNING_ITERATOR]);
|
||||
|
||||
impl LateLintPass<'_> for IterNotReturningIterator {
|
||||
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<'tcx>) {
|
||||
let name: &str = &impl_item.ident.name.as_str();
|
||||
if_chain! {
|
||||
if let ImplItemKind::Fn(fn_sig, _) = &impl_item.kind;
|
||||
let ret_ty = return_ty(cx, impl_item.hir_id());
|
||||
if matches!(name, "iter" | "iter_mut");
|
||||
if let [param] = cx.tcx.fn_arg_names(impl_item.def_id);
|
||||
if param.name == kw::SelfLower;
|
||||
if let Some(iter_trait_id) = cx.tcx.get_diagnostic_item(sym::Iterator);
|
||||
if !implements_trait(cx, ret_ty, iter_trait_id, &[]);
|
||||
|
||||
then {
|
||||
span_lint(
|
||||
cx,
|
||||
ITER_NOT_RETURNING_ITERATOR,
|
||||
fn_sig.span,
|
||||
&format!("this method is named `{}` but its return type does not implement `Iterator`", name),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -225,8 +225,8 @@ mod future_not_send;
|
|||
mod get_last_with_len;
|
||||
mod identity_op;
|
||||
mod if_let_mutex;
|
||||
mod if_let_some_result;
|
||||
mod if_not_else;
|
||||
mod if_then_panic;
|
||||
mod if_then_some_else_none;
|
||||
mod implicit_hasher;
|
||||
mod implicit_return;
|
||||
|
@ -241,6 +241,7 @@ mod int_plus_one;
|
|||
mod integer_division;
|
||||
mod invalid_upcast_comparisons;
|
||||
mod items_after_statements;
|
||||
mod iter_not_returning_iterator;
|
||||
mod large_const_arrays;
|
||||
mod large_enum_variant;
|
||||
mod large_stack_arrays;
|
||||
|
@ -262,6 +263,7 @@ mod map_clone;
|
|||
mod map_err_ignore;
|
||||
mod map_unit_fn;
|
||||
mod match_on_vec_items;
|
||||
mod match_result_ok;
|
||||
mod matches;
|
||||
mod mem_discriminant;
|
||||
mod mem_forget;
|
||||
|
@ -330,6 +332,7 @@ mod reference;
|
|||
mod regex;
|
||||
mod repeat_once;
|
||||
mod returns;
|
||||
mod same_name_method;
|
||||
mod self_assignment;
|
||||
mod self_named_constructors;
|
||||
mod semicolon_if_nothing_returned;
|
||||
|
@ -655,8 +658,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
get_last_with_len::GET_LAST_WITH_LEN,
|
||||
identity_op::IDENTITY_OP,
|
||||
if_let_mutex::IF_LET_MUTEX,
|
||||
if_let_some_result::IF_LET_SOME_RESULT,
|
||||
if_not_else::IF_NOT_ELSE,
|
||||
if_then_panic::IF_THEN_PANIC,
|
||||
if_then_some_else_none::IF_THEN_SOME_ELSE_NONE,
|
||||
implicit_hasher::IMPLICIT_HASHER,
|
||||
implicit_return::IMPLICIT_RETURN,
|
||||
|
@ -674,6 +677,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
integer_division::INTEGER_DIVISION,
|
||||
invalid_upcast_comparisons::INVALID_UPCAST_COMPARISONS,
|
||||
items_after_statements::ITEMS_AFTER_STATEMENTS,
|
||||
iter_not_returning_iterator::ITER_NOT_RETURNING_ITERATOR,
|
||||
large_const_arrays::LARGE_CONST_ARRAYS,
|
||||
large_enum_variant::LARGE_ENUM_VARIANT,
|
||||
large_stack_arrays::LARGE_STACK_ARRAYS,
|
||||
|
@ -723,6 +727,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
map_unit_fn::OPTION_MAP_UNIT_FN,
|
||||
map_unit_fn::RESULT_MAP_UNIT_FN,
|
||||
match_on_vec_items::MATCH_ON_VEC_ITEMS,
|
||||
match_result_ok::MATCH_RESULT_OK,
|
||||
matches::INFALLIBLE_DESTRUCTURING_MATCH,
|
||||
matches::MATCH_AS_REF,
|
||||
matches::MATCH_BOOL,
|
||||
|
@ -908,6 +913,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
repeat_once::REPEAT_ONCE,
|
||||
returns::LET_AND_RETURN,
|
||||
returns::NEEDLESS_RETURN,
|
||||
same_name_method::SAME_NAME_METHOD,
|
||||
self_assignment::SELF_ASSIGNMENT,
|
||||
self_named_constructors::SELF_NAMED_CONSTRUCTORS,
|
||||
semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED,
|
||||
|
@ -952,7 +958,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
transmuting_null::TRANSMUTING_NULL,
|
||||
try_err::TRY_ERR,
|
||||
types::BORROWED_BOX,
|
||||
types::BOX_VEC,
|
||||
types::BOX_COLLECTION,
|
||||
types::LINKEDLIST,
|
||||
types::OPTION_OPTION,
|
||||
types::RC_BUFFER,
|
||||
|
@ -1051,6 +1057,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
LintId::of(panic_unimplemented::UNIMPLEMENTED),
|
||||
LintId::of(panic_unimplemented::UNREACHABLE),
|
||||
LintId::of(pattern_type_mismatch::PATTERN_TYPE_MISMATCH),
|
||||
LintId::of(same_name_method::SAME_NAME_METHOD),
|
||||
LintId::of(shadow::SHADOW_REUSE),
|
||||
LintId::of(shadow::SHADOW_SAME),
|
||||
LintId::of(strings::STRING_ADD),
|
||||
|
@ -1104,6 +1111,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
LintId::of(infinite_iter::MAYBE_INFINITE_ITER),
|
||||
LintId::of(invalid_upcast_comparisons::INVALID_UPCAST_COMPARISONS),
|
||||
LintId::of(items_after_statements::ITEMS_AFTER_STATEMENTS),
|
||||
LintId::of(iter_not_returning_iterator::ITER_NOT_RETURNING_ITERATOR),
|
||||
LintId::of(large_stack_arrays::LARGE_STACK_ARRAYS),
|
||||
LintId::of(let_underscore::LET_UNDERSCORE_DROP),
|
||||
LintId::of(literal_representation::LARGE_DIGIT_GROUPS),
|
||||
|
@ -1126,6 +1134,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
LintId::of(methods::INEFFICIENT_TO_STRING),
|
||||
LintId::of(methods::MAP_FLATTEN),
|
||||
LintId::of(methods::MAP_UNWRAP_OR),
|
||||
LintId::of(misc::FLOAT_CMP),
|
||||
LintId::of(misc::USED_UNDERSCORE_BINDING),
|
||||
LintId::of(misc_early::UNSEPARATED_LITERAL_SUFFIX),
|
||||
LintId::of(mut_mut::MUT_MUT),
|
||||
|
@ -1134,6 +1143,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
LintId::of(needless_continue::NEEDLESS_CONTINUE),
|
||||
LintId::of(needless_for_each::NEEDLESS_FOR_EACH),
|
||||
LintId::of(needless_pass_by_value::NEEDLESS_PASS_BY_VALUE),
|
||||
LintId::of(non_expressive_names::MANY_SINGLE_CHAR_NAMES),
|
||||
LintId::of(non_expressive_names::SIMILAR_NAMES),
|
||||
LintId::of(pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE),
|
||||
LintId::of(pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF),
|
||||
|
@ -1249,7 +1259,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
LintId::of(get_last_with_len::GET_LAST_WITH_LEN),
|
||||
LintId::of(identity_op::IDENTITY_OP),
|
||||
LintId::of(if_let_mutex::IF_LET_MUTEX),
|
||||
LintId::of(if_let_some_result::IF_LET_SOME_RESULT),
|
||||
LintId::of(if_then_panic::IF_THEN_PANIC),
|
||||
LintId::of(indexing_slicing::OUT_OF_BOUNDS_INDEXING),
|
||||
LintId::of(infinite_iter::INFINITE_ITER),
|
||||
LintId::of(inherent_to_string::INHERENT_TO_STRING),
|
||||
|
@ -1292,6 +1302,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
LintId::of(map_clone::MAP_CLONE),
|
||||
LintId::of(map_unit_fn::OPTION_MAP_UNIT_FN),
|
||||
LintId::of(map_unit_fn::RESULT_MAP_UNIT_FN),
|
||||
LintId::of(match_result_ok::MATCH_RESULT_OK),
|
||||
LintId::of(matches::INFALLIBLE_DESTRUCTURING_MATCH),
|
||||
LintId::of(matches::MATCH_AS_REF),
|
||||
LintId::of(matches::MATCH_LIKE_MATCHES_MACRO),
|
||||
|
@ -1358,7 +1369,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
LintId::of(minmax::MIN_MAX),
|
||||
LintId::of(misc::CMP_NAN),
|
||||
LintId::of(misc::CMP_OWNED),
|
||||
LintId::of(misc::FLOAT_CMP),
|
||||
LintId::of(misc::MODULO_ONE),
|
||||
LintId::of(misc::SHORT_CIRCUIT_STATEMENT),
|
||||
LintId::of(misc::TOPLEVEL_REF_ARG),
|
||||
|
@ -1390,7 +1400,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
LintId::of(non_copy_const::BORROW_INTERIOR_MUTABLE_CONST),
|
||||
LintId::of(non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST),
|
||||
LintId::of(non_expressive_names::JUST_UNDERSCORES_AND_DIGITS),
|
||||
LintId::of(non_expressive_names::MANY_SINGLE_CHAR_NAMES),
|
||||
LintId::of(non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS),
|
||||
LintId::of(open_options::NONSENSICAL_OPEN_OPTIONS),
|
||||
LintId::of(option_env_unwrap::OPTION_ENV_UNWRAP),
|
||||
|
@ -1448,7 +1457,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
LintId::of(transmuting_null::TRANSMUTING_NULL),
|
||||
LintId::of(try_err::TRY_ERR),
|
||||
LintId::of(types::BORROWED_BOX),
|
||||
LintId::of(types::BOX_VEC),
|
||||
LintId::of(types::BOX_COLLECTION),
|
||||
LintId::of(types::REDUNDANT_ALLOCATION),
|
||||
LintId::of(types::TYPE_COMPLEXITY),
|
||||
LintId::of(types::VEC_BOX),
|
||||
|
@ -1504,7 +1513,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
LintId::of(functions::DOUBLE_MUST_USE),
|
||||
LintId::of(functions::MUST_USE_UNIT),
|
||||
LintId::of(functions::RESULT_UNIT_ERR),
|
||||
LintId::of(if_let_some_result::IF_LET_SOME_RESULT),
|
||||
LintId::of(if_then_panic::IF_THEN_PANIC),
|
||||
LintId::of(inherent_to_string::INHERENT_TO_STRING),
|
||||
LintId::of(len_zero::COMPARISON_TO_EMPTY),
|
||||
LintId::of(len_zero::LEN_WITHOUT_IS_EMPTY),
|
||||
|
@ -1520,6 +1529,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
LintId::of(manual_map::MANUAL_MAP),
|
||||
LintId::of(manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE),
|
||||
LintId::of(map_clone::MAP_CLONE),
|
||||
LintId::of(match_result_ok::MATCH_RESULT_OK),
|
||||
LintId::of(matches::INFALLIBLE_DESTRUCTURING_MATCH),
|
||||
LintId::of(matches::MATCH_LIKE_MATCHES_MACRO),
|
||||
LintId::of(matches::MATCH_OVERLAPPING_ARM),
|
||||
|
@ -1564,7 +1574,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
LintId::of(non_copy_const::BORROW_INTERIOR_MUTABLE_CONST),
|
||||
LintId::of(non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST),
|
||||
LintId::of(non_expressive_names::JUST_UNDERSCORES_AND_DIGITS),
|
||||
LintId::of(non_expressive_names::MANY_SINGLE_CHAR_NAMES),
|
||||
LintId::of(ptr::CMP_NULL),
|
||||
LintId::of(ptr::PTR_ARG),
|
||||
LintId::of(ptr_eq::PTR_EQ),
|
||||
|
@ -1724,7 +1733,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
LintId::of(methods::ZST_OFFSET),
|
||||
LintId::of(minmax::MIN_MAX),
|
||||
LintId::of(misc::CMP_NAN),
|
||||
LintId::of(misc::FLOAT_CMP),
|
||||
LintId::of(misc::MODULO_ONE),
|
||||
LintId::of(non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS),
|
||||
LintId::of(open_options::NONSENSICAL_OPEN_OPTIONS),
|
||||
|
@ -1787,7 +1795,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
LintId::of(redundant_clone::REDUNDANT_CLONE),
|
||||
LintId::of(slow_vector_initialization::SLOW_VECTOR_INITIALIZATION),
|
||||
LintId::of(stable_sort_primitive::STABLE_SORT_PRIMITIVE),
|
||||
LintId::of(types::BOX_VEC),
|
||||
LintId::of(types::BOX_COLLECTION),
|
||||
LintId::of(types::REDUNDANT_ALLOCATION),
|
||||
LintId::of(vec::USELESS_VEC),
|
||||
LintId::of(vec_init_then_push::VEC_INIT_THEN_PUSH),
|
||||
|
@ -1920,6 +1928,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
store.register_early_pass(move || Box::new(unnested_or_patterns::UnnestedOrPatterns::new(msrv)));
|
||||
|
||||
store.register_late_pass(|| Box::new(size_of_in_element_count::SizeOfInElementCount));
|
||||
store.register_late_pass(|| Box::new(same_name_method::SameNameMethod));
|
||||
store.register_late_pass(|| Box::new(map_clone::MapClone));
|
||||
store.register_late_pass(|| Box::new(map_err_ignore::MapErrIgnore));
|
||||
store.register_late_pass(|| Box::new(shadow::Shadow));
|
||||
|
@ -1952,7 +1961,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
store.register_late_pass(|| Box::new(empty_enum::EmptyEnum));
|
||||
store.register_late_pass(|| Box::new(absurd_extreme_comparisons::AbsurdExtremeComparisons));
|
||||
store.register_late_pass(|| Box::new(invalid_upcast_comparisons::InvalidUpcastComparisons));
|
||||
store.register_late_pass(|| Box::new(regex::Regex::default()));
|
||||
store.register_late_pass(|| Box::new(regex::Regex));
|
||||
store.register_late_pass(|| Box::new(copies::CopyAndPaste));
|
||||
store.register_late_pass(|| Box::new(copy_iterator::CopyIterator));
|
||||
store.register_late_pass(|| Box::new(format::UselessFormat));
|
||||
|
@ -1976,7 +1985,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
store.register_late_pass(|| Box::new(missing_doc::MissingDoc::new()));
|
||||
store.register_late_pass(|| Box::new(missing_inline::MissingInline));
|
||||
store.register_late_pass(move || Box::new(exhaustive_items::ExhaustiveItems));
|
||||
store.register_late_pass(|| Box::new(if_let_some_result::OkIfLet));
|
||||
store.register_late_pass(|| Box::new(match_result_ok::MatchResultOk));
|
||||
store.register_late_pass(|| Box::new(partialeq_ne_impl::PartialEqNeImpl));
|
||||
store.register_late_pass(|| Box::new(unused_io_amount::UnusedIoAmount));
|
||||
let enum_variant_size_threshold = conf.enum_variant_size_threshold;
|
||||
|
@ -2105,8 +2114,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
store.register_late_pass(|| Box::new(float_equality_without_abs::FloatEqualityWithoutAbs));
|
||||
store.register_late_pass(|| Box::new(semicolon_if_nothing_returned::SemicolonIfNothingReturned));
|
||||
store.register_late_pass(|| Box::new(async_yields_async::AsyncYieldsAsync));
|
||||
let disallowed_methods = conf.disallowed_methods.iter().cloned().collect::<FxHashSet<_>>();
|
||||
store.register_late_pass(move || Box::new(disallowed_method::DisallowedMethod::new(&disallowed_methods)));
|
||||
let disallowed_methods = conf.disallowed_methods.clone();
|
||||
store.register_late_pass(move || Box::new(disallowed_method::DisallowedMethod::new(disallowed_methods.clone())));
|
||||
store.register_early_pass(|| Box::new(asm_syntax::InlineAsmX86AttSyntax));
|
||||
store.register_early_pass(|| Box::new(asm_syntax::InlineAsmX86IntelSyntax));
|
||||
store.register_late_pass(|| Box::new(undropped_manually_drops::UndroppedManuallyDrops));
|
||||
|
@ -2131,6 +2140,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||
store.register_late_pass(|| Box::new(strlen_on_c_strings::StrlenOnCStrings));
|
||||
store.register_late_pass(move || Box::new(self_named_constructors::SelfNamedConstructors));
|
||||
store.register_late_pass(move || Box::new(feature_name::FeatureName));
|
||||
store.register_late_pass(move || Box::new(iter_not_returning_iterator::IterNotReturningIterator));
|
||||
store.register_late_pass(move || Box::new(if_then_panic::IfThenPanic));
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
|
@ -2186,6 +2197,7 @@ pub fn register_renamed(ls: &mut rustc_lint::LintStore) {
|
|||
ls.register_renamed("clippy::cyclomatic_complexity", "clippy::cognitive_complexity");
|
||||
ls.register_renamed("clippy::const_static_lifetime", "clippy::redundant_static_lifetimes");
|
||||
ls.register_renamed("clippy::option_and_then_some", "clippy::bind_instead_of_map");
|
||||
ls.register_renamed("clippy::box_vec", "clippy::box_collection");
|
||||
ls.register_renamed("clippy::block_in_if_condition_expr", "clippy::blocks_in_if_conditions");
|
||||
ls.register_renamed("clippy::block_in_if_condition_stmt", "clippy::blocks_in_if_conditions");
|
||||
ls.register_renamed("clippy::option_map_unwrap_or", "clippy::map_unwrap_or");
|
||||
|
@ -2200,6 +2212,7 @@ pub fn register_renamed(ls: &mut rustc_lint::LintStore) {
|
|||
ls.register_renamed("clippy::identity_conversion", "clippy::useless_conversion");
|
||||
ls.register_renamed("clippy::zero_width_space", "clippy::invisible_characters");
|
||||
ls.register_renamed("clippy::single_char_push_str", "clippy::single_char_add_str");
|
||||
ls.register_renamed("clippy::if_let_some_result", "clippy::match_result_ok");
|
||||
|
||||
// uplifted lints
|
||||
ls.register_renamed("clippy::invalid_ref", "invalid_value");
|
||||
|
|
|
@ -10,12 +10,7 @@ use rustc_middle::ty;
|
|||
use rustc_span::sym;
|
||||
|
||||
/// Checks for the `FOR_KV_MAP` lint.
|
||||
pub(super) fn check<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
pat: &'tcx Pat<'_>,
|
||||
arg: &'tcx Expr<'_>,
|
||||
body: &'tcx Expr<'_>,
|
||||
) {
|
||||
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, arg: &'tcx Expr<'_>, body: &'tcx Expr<'_>) {
|
||||
let pat_span = pat.span;
|
||||
|
||||
if let PatKind::Tuple(pat, _) = pat.kind {
|
||||
|
|
|
@ -65,7 +65,7 @@ fn extract_first_expr<'tcx>(block: &Block<'tcx>) -> Option<&'tcx Expr<'tcx>> {
|
|||
fn is_simple_break_expr(expr: &Expr<'_>) -> bool {
|
||||
match expr.kind {
|
||||
ExprKind::Break(dest, ref passed_expr) if dest.label.is_none() && passed_expr.is_none() => true,
|
||||
ExprKind::Block(b, _) => extract_first_expr(b).map_or(false, |subexpr| is_simple_break_expr(subexpr)),
|
||||
ExprKind::Block(b, _) => extract_first_expr(b).map_or(false, is_simple_break_expr),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ use clippy_utils::{
|
|||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::intravisit::{walk_expr, ErasedMap, NestedVisitorMap, Visitor};
|
||||
use rustc_hir::{def::Res, Expr, ExprKind, HirId, Local, Mutability, PatKind, QPath, UnOp};
|
||||
use rustc_hir::{def::Res, Expr, ExprKind, HirId, Local, PatKind, QPath, UnOp};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_span::{symbol::sym, Span, Symbol};
|
||||
|
||||
|
@ -47,13 +47,8 @@ pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
|||
// If the iterator is a field or the iterator is accessed after the loop is complete it needs to be
|
||||
// borrowed mutably. TODO: If the struct can be partially moved from and the struct isn't used
|
||||
// afterwards a mutable borrow of a field isn't necessary.
|
||||
let ref_mut = if !iter_expr.fields.is_empty() || needs_mutable_borrow(cx, &iter_expr, loop_expr) {
|
||||
if cx.typeck_results().node_type(iter_expr.hir_id).ref_mutability() == Some(Mutability::Mut) {
|
||||
// Reborrow for mutable references. It may not be possible to get a mutable reference here.
|
||||
"&mut *"
|
||||
} else {
|
||||
"&mut "
|
||||
}
|
||||
let by_ref = if !iter_expr.fields.is_empty() || needs_mutable_borrow(cx, &iter_expr, loop_expr) {
|
||||
".by_ref()"
|
||||
} else {
|
||||
""
|
||||
};
|
||||
|
@ -65,7 +60,7 @@ pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
|||
expr.span.with_hi(scrutinee_expr.span.hi()),
|
||||
"this loop could be written as a `for` loop",
|
||||
"try",
|
||||
format!("for {} in {}{}", loop_var, ref_mut, iterator),
|
||||
format!("for {} in {}{}", loop_var, iterator, by_ref),
|
||||
applicability,
|
||||
);
|
||||
}
|
||||
|
@ -74,8 +69,6 @@ pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
|||
struct IterExpr {
|
||||
/// The span of the whole expression, not just the path and fields stored here.
|
||||
span: Span,
|
||||
/// The HIR id of the whole expression, not just the path and fields stored here.
|
||||
hir_id: HirId,
|
||||
/// The fields used, in order of child to parent.
|
||||
fields: Vec<Symbol>,
|
||||
/// The path being used.
|
||||
|
@ -86,14 +79,12 @@ struct IterExpr {
|
|||
/// the expression might have side effects.
|
||||
fn try_parse_iter_expr(cx: &LateContext<'_>, mut e: &Expr<'_>) -> Option<IterExpr> {
|
||||
let span = e.span;
|
||||
let hir_id = e.hir_id;
|
||||
let mut fields = Vec::new();
|
||||
loop {
|
||||
match e.kind {
|
||||
ExprKind::Path(ref path) => {
|
||||
break Some(IterExpr {
|
||||
span,
|
||||
hir_id,
|
||||
fields,
|
||||
path: cx.qpath_res(path, e.hir_id),
|
||||
});
|
||||
|
|
|
@ -63,29 +63,24 @@ impl MacroUseImports {
|
|||
fn push_unique_macro(&mut self, cx: &LateContext<'_>, span: Span) {
|
||||
let call_site = span.source_callsite();
|
||||
let name = snippet(cx, cx.sess().source_map().span_until_char(call_site, '!'), "_");
|
||||
if let Some(_callee) = span.source_callee() {
|
||||
if !self.collected.contains(&call_site) {
|
||||
let name = if name.contains("::") {
|
||||
name.split("::").last().unwrap().to_string()
|
||||
} else {
|
||||
name.to_string()
|
||||
};
|
||||
if span.source_callee().is_some() && !self.collected.contains(&call_site) {
|
||||
let name = if name.contains("::") {
|
||||
name.split("::").last().unwrap().to_string()
|
||||
} else {
|
||||
name.to_string()
|
||||
};
|
||||
|
||||
self.mac_refs.push(MacroRefData::new(name));
|
||||
self.collected.insert(call_site);
|
||||
}
|
||||
self.mac_refs.push(MacroRefData::new(name));
|
||||
self.collected.insert(call_site);
|
||||
}
|
||||
}
|
||||
|
||||
fn push_unique_macro_pat_ty(&mut self, cx: &LateContext<'_>, span: Span) {
|
||||
let call_site = span.source_callsite();
|
||||
let name = snippet(cx, cx.sess().source_map().span_until_char(call_site, '!'), "_");
|
||||
if let Some(_callee) = span.source_callee() {
|
||||
if !self.collected.contains(&call_site) {
|
||||
self.mac_refs
|
||||
.push(MacroRefData::new(name.to_string()));
|
||||
self.collected.insert(call_site);
|
||||
}
|
||||
if span.source_callee().is_some() && !self.collected.contains(&call_site) {
|
||||
self.mac_refs.push(MacroRefData::new(name.to_string()));
|
||||
self.collected.insert(call_site);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,40 +12,51 @@ use rustc_span::sym;
|
|||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
///* Checks for unnecessary `ok()` in if let.
|
||||
/// Checks for unnecessary `ok()` in `while let`.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// Calling `ok()` in if let is unnecessary, instead match
|
||||
/// Calling `ok()` in `while let` is unnecessary, instead match
|
||||
/// on `Ok(pat)`
|
||||
///
|
||||
/// ### Example
|
||||
/// ```ignore
|
||||
/// for i in iter {
|
||||
/// if let Some(value) = i.parse().ok() {
|
||||
/// vec.push(value)
|
||||
/// }
|
||||
/// while let Some(value) = iter.next().ok() {
|
||||
/// vec.push(value)
|
||||
/// }
|
||||
/// ```
|
||||
/// Could be written:
|
||||
///
|
||||
/// ```ignore
|
||||
/// for i in iter {
|
||||
/// if let Ok(value) = i.parse() {
|
||||
/// vec.push(value)
|
||||
/// }
|
||||
/// if let Some(valie) = iter.next().ok() {
|
||||
/// vec.push(value)
|
||||
/// }
|
||||
/// ```
|
||||
pub IF_LET_SOME_RESULT,
|
||||
/// Use instead:
|
||||
/// ```ignore
|
||||
/// while let Ok(value) = iter.next() {
|
||||
/// vec.push(value)
|
||||
/// }
|
||||
///
|
||||
/// if let Ok(value) = iter.next() {
|
||||
/// vec.push_value)
|
||||
/// }
|
||||
/// ```
|
||||
pub MATCH_RESULT_OK,
|
||||
style,
|
||||
"usage of `ok()` in `if let Some(pat)` statements is unnecessary, match on `Ok(pat)` instead"
|
||||
"usage of `ok()` in `let Some(pat)` statements is unnecessary, match on `Ok(pat)` instead"
|
||||
}
|
||||
|
||||
declare_lint_pass!(OkIfLet => [IF_LET_SOME_RESULT]);
|
||||
declare_lint_pass!(MatchResultOk => [MATCH_RESULT_OK]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for OkIfLet {
|
||||
impl<'tcx> LateLintPass<'tcx> for MatchResultOk {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
if_chain! { //begin checking variables
|
||||
if let Some(higher::IfLet { let_pat, let_expr, .. }) = higher::IfLet::hir(cx, expr);
|
||||
let (let_pat, let_expr, ifwhile) =
|
||||
if let Some(higher::IfLet { let_pat, let_expr, .. }) = higher::IfLet::hir(cx, expr) {
|
||||
(let_pat, let_expr, "if")
|
||||
} else if let Some(higher::WhileLet { let_pat, let_expr, .. }) = higher::WhileLet::hir(expr) {
|
||||
(let_pat, let_expr, "while")
|
||||
} else {
|
||||
return;
|
||||
};
|
||||
|
||||
if_chain! {
|
||||
if let ExprKind::MethodCall(_, ok_span, [ref 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() methoduse std::marker::Sized;
|
||||
|
@ -53,17 +64,19 @@ impl<'tcx> LateLintPass<'tcx> for OkIfLet {
|
|||
if rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_path(x, false)) == "Some";
|
||||
|
||||
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_span), "", &mut applicability);
|
||||
let sugg = format!(
|
||||
"if let Ok({}) = {}",
|
||||
"{} let Ok({}) = {}",
|
||||
ifwhile,
|
||||
some_expr_string,
|
||||
trimmed_ok.trim().trim_end_matches('.'),
|
||||
);
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
IF_LET_SOME_RESULT,
|
||||
MATCH_RESULT_OK,
|
||||
expr.span.with_hi(let_expr.span.hi()),
|
||||
"matching on `Some` with `ok()` is redundant",
|
||||
&format!("consider matching on `Ok({})` and removing the call to `ok` instead", some_expr_string),
|
|
@ -183,8 +183,8 @@ declare_clippy_lint! {
|
|||
/// ```rust
|
||||
/// let x = 5;
|
||||
/// match x {
|
||||
/// 1...10 => println!("1 ... 10"),
|
||||
/// 5...15 => println!("5 ... 15"),
|
||||
/// 1..=10 => println!("1 ... 10"),
|
||||
/// 5..=15 => println!("5 ... 15"),
|
||||
/// _ => (),
|
||||
/// }
|
||||
/// ```
|
||||
|
|
|
@ -17,32 +17,25 @@ pub(super) fn check(cx: &LateContext<'_>, method_name: &str, expr: &Expr<'_>, se
|
|||
}
|
||||
|
||||
let ctxt = expr.span.ctxt();
|
||||
let usage = match parse_iter_usage(cx, ctxt, cx.tcx.hir().parent_iter(expr.hir_id)) {
|
||||
let (method_name, msg, reverse) = if method_name == "splitn" {
|
||||
("split_once", "manual implementation of `split_once`", false)
|
||||
} else {
|
||||
("rsplit_once", "manual implementation of `rsplit_once`", true)
|
||||
};
|
||||
let usage = match parse_iter_usage(cx, ctxt, cx.tcx.hir().parent_iter(expr.hir_id), reverse) {
|
||||
Some(x) => x,
|
||||
None => return,
|
||||
};
|
||||
let (method_name, msg) = if method_name == "splitn" {
|
||||
("split_once", "manual implementation of `split_once`")
|
||||
} else {
|
||||
("rsplit_once", "manual implementation of `rsplit_once`")
|
||||
};
|
||||
|
||||
let mut app = Applicability::MachineApplicable;
|
||||
let self_snip = snippet_with_context(cx, self_arg.span, ctxt, "..", &mut app).0;
|
||||
let pat_snip = snippet_with_context(cx, pat_arg.span, ctxt, "..", &mut app).0;
|
||||
|
||||
match usage.kind {
|
||||
let sugg = match usage.kind {
|
||||
IterUsageKind::NextTuple => {
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
MANUAL_SPLIT_ONCE,
|
||||
usage.span,
|
||||
msg,
|
||||
"try this",
|
||||
format!("{}.{}({})", self_snip, method_name, pat_snip),
|
||||
app,
|
||||
);
|
||||
format!("{}.{}({})", self_snip, method_name, pat_snip)
|
||||
},
|
||||
IterUsageKind::RNextTuple => format!("{}.{}({}).map(|(x, y)| (y, x))", self_snip, method_name, pat_snip),
|
||||
IterUsageKind::Next => {
|
||||
let self_deref = {
|
||||
let adjust = cx.typeck_results().expr_adjustments(self_arg);
|
||||
|
@ -58,7 +51,7 @@ pub(super) fn check(cx: &LateContext<'_>, method_name: &str, expr: &Expr<'_>, se
|
|||
"*".repeat(adjust.len() - 2)
|
||||
}
|
||||
};
|
||||
let sugg = if usage.unwrap_kind.is_some() {
|
||||
if usage.unwrap_kind.is_some() {
|
||||
format!(
|
||||
"{}.{}({}).map_or({}{}, |x| x.0)",
|
||||
&self_snip, method_name, pat_snip, self_deref, &self_snip
|
||||
|
@ -68,9 +61,7 @@ pub(super) fn check(cx: &LateContext<'_>, method_name: &str, expr: &Expr<'_>, se
|
|||
"Some({}.{}({}).map_or({}{}, |x| x.0))",
|
||||
&self_snip, method_name, pat_snip, self_deref, &self_snip
|
||||
)
|
||||
};
|
||||
|
||||
span_lint_and_sugg(cx, MANUAL_SPLIT_ONCE, usage.span, msg, "try this", sugg, app);
|
||||
}
|
||||
},
|
||||
IterUsageKind::Second => {
|
||||
let access_str = match usage.unwrap_kind {
|
||||
|
@ -78,23 +69,18 @@ pub(super) fn check(cx: &LateContext<'_>, method_name: &str, expr: &Expr<'_>, se
|
|||
Some(UnwrapKind::QuestionMark) => "?.1",
|
||||
None => ".map(|x| x.1)",
|
||||
};
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
MANUAL_SPLIT_ONCE,
|
||||
usage.span,
|
||||
msg,
|
||||
"try this",
|
||||
format!("{}.{}({}){}", self_snip, method_name, pat_snip, access_str),
|
||||
app,
|
||||
);
|
||||
format!("{}.{}({}){}", self_snip, method_name, pat_snip, access_str)
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
span_lint_and_sugg(cx, MANUAL_SPLIT_ONCE, usage.span, msg, "try this", sugg, app);
|
||||
}
|
||||
|
||||
enum IterUsageKind {
|
||||
Next,
|
||||
Second,
|
||||
NextTuple,
|
||||
RNextTuple,
|
||||
}
|
||||
|
||||
enum UnwrapKind {
|
||||
|
@ -108,10 +94,12 @@ struct IterUsage {
|
|||
span: Span,
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_lines)]
|
||||
fn parse_iter_usage(
|
||||
cx: &LateContext<'tcx>,
|
||||
ctxt: SyntaxContext,
|
||||
mut iter: impl Iterator<Item = (HirId, Node<'tcx>)>,
|
||||
reverse: bool,
|
||||
) -> Option<IterUsage> {
|
||||
let (kind, span) = match iter.next() {
|
||||
Some((_, Node::Expr(e))) if e.span.ctxt() == ctxt => {
|
||||
|
@ -124,20 +112,30 @@ fn parse_iter_usage(
|
|||
let iter_id = cx.tcx.get_diagnostic_item(sym::Iterator)?;
|
||||
|
||||
match (&*name.ident.as_str(), args) {
|
||||
("next", []) if cx.tcx.trait_of_item(did) == Some(iter_id) => (IterUsageKind::Next, e.span),
|
||||
("next", []) if cx.tcx.trait_of_item(did) == Some(iter_id) => {
|
||||
if reverse {
|
||||
(IterUsageKind::Second, e.span)
|
||||
} else {
|
||||
(IterUsageKind::Next, e.span)
|
||||
}
|
||||
},
|
||||
("next_tuple", []) => {
|
||||
if_chain! {
|
||||
return if_chain! {
|
||||
if match_def_path(cx, did, &paths::ITERTOOLS_NEXT_TUPLE);
|
||||
if let ty::Adt(adt_def, subs) = cx.typeck_results().expr_ty(e).kind();
|
||||
if cx.tcx.is_diagnostic_item(sym::option_type, adt_def.did);
|
||||
if let ty::Tuple(subs) = subs.type_at(0).kind();
|
||||
if subs.len() == 2;
|
||||
then {
|
||||
return Some(IterUsage { kind: IterUsageKind::NextTuple, span: e.span, unwrap_kind: None });
|
||||
Some(IterUsage {
|
||||
kind: if reverse { IterUsageKind::RNextTuple } else { IterUsageKind::NextTuple },
|
||||
span: e.span,
|
||||
unwrap_kind: None
|
||||
})
|
||||
} else {
|
||||
return None;
|
||||
None
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
("nth" | "skip", [idx_expr]) if cx.tcx.trait_of_item(did) == Some(iter_id) => {
|
||||
if let Some((Constant::Int(idx), _)) = constant(cx, cx.typeck_results(), idx_expr) {
|
||||
|
@ -158,7 +156,7 @@ fn parse_iter_usage(
|
|||
}
|
||||
}
|
||||
};
|
||||
match idx {
|
||||
match if reverse { idx ^ 1 } else { idx } {
|
||||
0 => (IterUsageKind::Next, span),
|
||||
1 => (IterUsageKind::Second, span),
|
||||
_ => return None,
|
||||
|
|
|
@ -264,6 +264,8 @@ declare_clippy_lint! {
|
|||
/// The method signature is controlled by the trait and often `&self` is required for all types that implement the trait
|
||||
/// (see e.g. the `std::string::ToString` trait).
|
||||
///
|
||||
/// Clippy allows `Pin<&Self>` and `Pin<&mut Self>` if `&self` and `&mut self` is required.
|
||||
///
|
||||
/// Please find more info here:
|
||||
/// https://rust-lang.github.io/api-guidelines/naming.html#ad-hoc-conversions-follow-as_-to_-into_-conventions-c-conv
|
||||
///
|
||||
|
|
|
@ -113,7 +113,7 @@ declare_clippy_lint! {
|
|||
/// if (y - x).abs() > error_margin { }
|
||||
/// ```
|
||||
pub FLOAT_CMP,
|
||||
correctness,
|
||||
pedantic,
|
||||
"using `==` or `!=` on float values instead of comparing difference with an epsilon"
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ use clippy_utils::trait_ref_of_method;
|
|||
use rustc_hir as hir;
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty::TypeFoldable;
|
||||
use rustc_middle::ty::{Adt, Array, RawPtr, Ref, Slice, Tuple, Ty, TypeAndMut};
|
||||
use rustc_middle::ty::{Adt, Array, Ref, Slice, Tuple, Ty};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::source_map::Span;
|
||||
use rustc_span::symbol::sym;
|
||||
|
@ -19,10 +19,29 @@ declare_clippy_lint! {
|
|||
/// so having types with interior mutability is a bad idea.
|
||||
///
|
||||
/// ### Known problems
|
||||
/// It's correct to use a struct, that contains interior mutability
|
||||
/// as a key, when its `Hash` implementation doesn't access any of the interior mutable types.
|
||||
/// However, this lint is unable to recognize this, so it causes a false positive in theses cases.
|
||||
/// The `bytes` crate is a great example of this.
|
||||
///
|
||||
/// #### False Positives
|
||||
/// It's correct to use a struct that contains interior mutability as a key, when its
|
||||
/// implementation of `Hash` or `Ord` doesn't access any of the interior mutable types.
|
||||
/// However, this lint is unable to recognize this, so it will often cause false positives in
|
||||
/// theses cases. The `bytes` crate is a great example of this.
|
||||
///
|
||||
/// #### False Negatives
|
||||
/// For custom `struct`s/`enum`s, this lint is unable to check for interior mutability behind
|
||||
/// indirection. For example, `struct BadKey<'a>(&'a Cell<usize>)` will be seen as immutable
|
||||
/// and cause a false negative if its implementation of `Hash`/`Ord` accesses the `Cell`.
|
||||
///
|
||||
/// This lint does check a few cases for indirection. Firstly, using some standard library
|
||||
/// types (`Option`, `Result`, `Box`, `Rc`, `Arc`, `Vec`, `VecDeque`, `BTreeMap` and
|
||||
/// `BTreeSet`) directly as keys (e.g. in `HashMap<Box<Cell<usize>>, ()>`) **will** trigger the
|
||||
/// lint, because the impls of `Hash`/`Ord` for these types directly call `Hash`/`Ord` on their
|
||||
/// contained type.
|
||||
///
|
||||
/// Secondly, the implementations of `Hash` and `Ord` for raw pointers (`*const T` or `*mut T`)
|
||||
/// apply only to the **address** of the contained value. Therefore, interior mutability
|
||||
/// behind raw pointers (e.g. in `HashSet<*mut Cell<usize>>`) can't impact the value of `Hash`
|
||||
/// or `Ord`, and therefore will not trigger this link. For more info, see issue
|
||||
/// [#6745](https://github.com/rust-lang/rust-clippy/issues/6745).
|
||||
///
|
||||
/// ### Example
|
||||
/// ```rust
|
||||
|
@ -103,30 +122,52 @@ fn check_sig<'tcx>(cx: &LateContext<'tcx>, item_hir_id: hir::HirId, decl: &hir::
|
|||
fn check_ty<'tcx>(cx: &LateContext<'tcx>, span: Span, ty: Ty<'tcx>) {
|
||||
let ty = ty.peel_refs();
|
||||
if let Adt(def, substs) = ty.kind() {
|
||||
if [sym::hashmap_type, sym::BTreeMap, sym::hashset_type, sym::BTreeMap]
|
||||
let is_keyed_type = [sym::hashmap_type, sym::BTreeMap, sym::hashset_type, sym::BTreeSet]
|
||||
.iter()
|
||||
.any(|diag_item| cx.tcx.is_diagnostic_item(*diag_item, def.did))
|
||||
&& is_mutable_type(cx, substs.type_at(0), span)
|
||||
{
|
||||
.any(|diag_item| cx.tcx.is_diagnostic_item(*diag_item, def.did));
|
||||
if is_keyed_type && is_interior_mutable_type(cx, substs.type_at(0), span) {
|
||||
span_lint(cx, MUTABLE_KEY_TYPE, span, "mutable key type");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_mutable_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, span: Span) -> bool {
|
||||
/// Determines if a type contains interior mutability which would affect its implementation of
|
||||
/// [`Hash`] or [`Ord`].
|
||||
fn is_interior_mutable_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, span: Span) -> bool {
|
||||
match *ty.kind() {
|
||||
RawPtr(TypeAndMut { ty: inner_ty, mutbl }) | Ref(_, inner_ty, mutbl) => {
|
||||
mutbl == hir::Mutability::Mut || is_mutable_type(cx, inner_ty, span)
|
||||
},
|
||||
Slice(inner_ty) => is_mutable_type(cx, inner_ty, span),
|
||||
Ref(_, inner_ty, mutbl) => mutbl == hir::Mutability::Mut || is_interior_mutable_type(cx, inner_ty, span),
|
||||
Slice(inner_ty) => is_interior_mutable_type(cx, inner_ty, span),
|
||||
Array(inner_ty, size) => {
|
||||
size.try_eval_usize(cx.tcx, cx.param_env).map_or(true, |u| u != 0) && is_mutable_type(cx, inner_ty, span)
|
||||
size.try_eval_usize(cx.tcx, cx.param_env).map_or(true, |u| u != 0)
|
||||
&& is_interior_mutable_type(cx, inner_ty, span)
|
||||
},
|
||||
Tuple(..) => ty.tuple_fields().any(|ty| is_mutable_type(cx, ty, span)),
|
||||
Adt(..) => {
|
||||
!ty.has_escaping_bound_vars()
|
||||
&& cx.tcx.layout_of(cx.param_env.and(ty)).is_ok()
|
||||
&& !ty.is_freeze(cx.tcx.at(span), cx.param_env)
|
||||
Tuple(..) => ty.tuple_fields().any(|ty| is_interior_mutable_type(cx, ty, span)),
|
||||
Adt(def, substs) => {
|
||||
// Special case for collections in `std` who's impl of `Hash` or `Ord` delegates to
|
||||
// that of their type parameters. Note: we don't include `HashSet` and `HashMap`
|
||||
// because they have no impl for `Hash` or `Ord`.
|
||||
let is_std_collection = [
|
||||
sym::option_type,
|
||||
sym::result_type,
|
||||
sym::LinkedList,
|
||||
sym::vec_type,
|
||||
sym::vecdeque_type,
|
||||
sym::BTreeMap,
|
||||
sym::BTreeSet,
|
||||
sym::Rc,
|
||||
sym::Arc,
|
||||
]
|
||||
.iter()
|
||||
.any(|diag_item| cx.tcx.is_diagnostic_item(*diag_item, def.did));
|
||||
let is_box = Some(def.did) == cx.tcx.lang_items().owned_box();
|
||||
if is_std_collection || is_box {
|
||||
// The type is mutable if any of its type parameters are
|
||||
substs.types().any(|ty| is_interior_mutable_type(cx, ty, span))
|
||||
} else {
|
||||
!ty.has_escaping_bound_vars()
|
||||
&& cx.tcx.layout_of(cx.param_env.and(ty)).is_ok()
|
||||
&& !ty.is_freeze(cx.tcx.at(span), cx.param_env)
|
||||
}
|
||||
},
|
||||
_ => false,
|
||||
}
|
||||
|
|
|
@ -104,7 +104,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrow {
|
|||
if e.span.from_expansion() {
|
||||
return;
|
||||
}
|
||||
if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = e.kind {
|
||||
if let ExprKind::AddrOf(BorrowKind::Ref, mutability, inner) = e.kind {
|
||||
if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty(inner).kind() {
|
||||
for adj3 in cx.typeck_results().expr_adjustments(e).windows(3) {
|
||||
if let [Adjustment {
|
||||
|
@ -116,14 +116,20 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrow {
|
|||
..
|
||||
}] = *adj3
|
||||
{
|
||||
let help_msg_ty = if matches!(mutability, Mutability::Not) {
|
||||
format!("&{}", ty)
|
||||
} else {
|
||||
format!("&mut {}", ty)
|
||||
};
|
||||
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
NEEDLESS_BORROW,
|
||||
e.span,
|
||||
&format!(
|
||||
"this expression borrows a reference (`&{}`) that is immediately dereferenced \
|
||||
"this expression borrows a reference (`{}`) that is immediately dereferenced \
|
||||
by the compiler",
|
||||
ty
|
||||
help_msg_ty
|
||||
),
|
||||
|diag| {
|
||||
if let Some(snippet) = snippet_opt(cx, inner.span) {
|
||||
|
|
|
@ -43,7 +43,7 @@ declare_clippy_lint! {
|
|||
/// let (a, b, c, d, e, f, g) = (...);
|
||||
/// ```
|
||||
pub MANY_SINGLE_CHAR_NAMES,
|
||||
style,
|
||||
pedantic,
|
||||
"too many single character bindings"
|
||||
}
|
||||
|
||||
|
|
|
@ -372,7 +372,7 @@ fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_id:
|
|||
for (_, ref mutbl, ref argspan) in decl
|
||||
.inputs
|
||||
.iter()
|
||||
.filter_map(|ty| get_rptr_lm(ty))
|
||||
.filter_map(get_rptr_lm)
|
||||
.filter(|&(lt, _, _)| lt.name == out.name)
|
||||
{
|
||||
if *mutbl == Mutability::Mut {
|
||||
|
|
|
@ -5,7 +5,7 @@ use if_chain::if_chain;
|
|||
use rustc_ast::ast::{LitKind, StrStyle};
|
||||
use rustc_hir::{BorrowKind, Expr, ExprKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::source_map::{BytePos, Span};
|
||||
use std::convert::TryFrom;
|
||||
|
||||
|
@ -51,10 +51,7 @@ declare_clippy_lint! {
|
|||
"trivial regular expressions"
|
||||
}
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
pub struct Regex {}
|
||||
|
||||
impl_lint_pass!(Regex => [INVALID_REGEX, TRIVIAL_REGEX]);
|
||||
declare_lint_pass!(Regex => [INVALID_REGEX, TRIVIAL_REGEX]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for Regex {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
|
|
|
@ -11,6 +11,7 @@ use rustc_middle::hir::map::Map;
|
|||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_middle::ty::subst::GenericArgKind;
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::hygiene::DesugaringKind;
|
||||
use rustc_span::source_map::Span;
|
||||
use rustc_span::sym;
|
||||
|
||||
|
@ -199,7 +200,9 @@ fn check_final_expr<'tcx>(
|
|||
check_block_return(cx, ifblock);
|
||||
}
|
||||
if let Some(else_clause) = else_clause_opt {
|
||||
check_final_expr(cx, else_clause, None, RetReplacement::Empty);
|
||||
if expr.span.desugaring_kind() != Some(DesugaringKind::LetElse) {
|
||||
check_final_expr(cx, else_clause, None, RetReplacement::Empty);
|
||||
}
|
||||
}
|
||||
},
|
||||
// a match expr, check all arms
|
||||
|
|
160
clippy_lints/src/same_name_method.rs
Normal file
160
clippy_lints/src/same_name_method.rs
Normal file
|
@ -0,0 +1,160 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::{Crate, Impl, ItemKind, Node, Path, QPath, TraitRef, TyKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty::AssocKind;
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::symbol::Symbol;
|
||||
use rustc_span::Span;
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// It lints if a struct has two method with same time:
|
||||
/// one from a trait, another not from trait.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// Confusing.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```rust
|
||||
/// trait T {
|
||||
/// fn foo(&self) {}
|
||||
/// }
|
||||
///
|
||||
/// struct S;
|
||||
///
|
||||
/// impl T for S {
|
||||
/// fn foo(&self) {}
|
||||
/// }
|
||||
///
|
||||
/// impl S {
|
||||
/// fn foo(&self) {}
|
||||
/// }
|
||||
/// ```
|
||||
pub SAME_NAME_METHOD,
|
||||
restriction,
|
||||
"two method with same name"
|
||||
}
|
||||
|
||||
declare_lint_pass!(SameNameMethod => [SAME_NAME_METHOD]);
|
||||
|
||||
struct ExistingName {
|
||||
impl_methods: BTreeMap<Symbol, Span>,
|
||||
trait_methods: BTreeMap<Symbol, Vec<Span>>,
|
||||
}
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for SameNameMethod {
|
||||
fn check_crate_post(&mut self, cx: &LateContext<'tcx>, krate: &'tcx Crate<'tcx>) {
|
||||
let mut map = FxHashMap::<Res, ExistingName>::default();
|
||||
|
||||
for item in krate.items() {
|
||||
if let ItemKind::Impl(Impl {
|
||||
items,
|
||||
of_trait,
|
||||
self_ty,
|
||||
..
|
||||
}) = &item.kind
|
||||
{
|
||||
if let TyKind::Path(QPath::Resolved(_, Path { res, .. })) = self_ty.kind {
|
||||
if !map.contains_key(res) {
|
||||
map.insert(
|
||||
*res,
|
||||
ExistingName {
|
||||
impl_methods: BTreeMap::new(),
|
||||
trait_methods: BTreeMap::new(),
|
||||
},
|
||||
);
|
||||
}
|
||||
let existing_name = map.get_mut(res).unwrap();
|
||||
|
||||
match of_trait {
|
||||
Some(trait_ref) => {
|
||||
let mut methods_in_trait: BTreeSet<Symbol> = if_chain! {
|
||||
if let Some(Node::TraitRef(TraitRef { path, .. })) =
|
||||
cx.tcx.hir().find(trait_ref.hir_ref_id);
|
||||
if let Res::Def(DefKind::Trait, did) = path.res;
|
||||
then{
|
||||
// FIXME: if
|
||||
// `rustc_middle::ty::assoc::AssocItems::items` is public,
|
||||
// we can iterate its keys instead of `in_definition_order`,
|
||||
// which's more efficient
|
||||
cx.tcx
|
||||
.associated_items(did)
|
||||
.in_definition_order()
|
||||
.filter(|assoc_item| {
|
||||
matches!(assoc_item.kind, AssocKind::Fn)
|
||||
})
|
||||
.map(|assoc_item| assoc_item.ident.name)
|
||||
.collect()
|
||||
}else{
|
||||
BTreeSet::new()
|
||||
}
|
||||
};
|
||||
|
||||
let mut check_trait_method = |method_name: Symbol, trait_method_span: Span| {
|
||||
if let Some(impl_span) = existing_name.impl_methods.get(&method_name) {
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
SAME_NAME_METHOD,
|
||||
*impl_span,
|
||||
"method's name is same to an existing method in a trait",
|
||||
|diag| {
|
||||
diag.span_note(
|
||||
trait_method_span,
|
||||
&format!("existing `{}` defined here", method_name),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
if let Some(v) = existing_name.trait_methods.get_mut(&method_name) {
|
||||
v.push(trait_method_span);
|
||||
} else {
|
||||
existing_name.trait_methods.insert(method_name, vec![trait_method_span]);
|
||||
}
|
||||
};
|
||||
|
||||
for impl_item_ref in (*items).iter().filter(|impl_item_ref| {
|
||||
matches!(impl_item_ref.kind, rustc_hir::AssocItemKind::Fn { .. })
|
||||
}) {
|
||||
let method_name = impl_item_ref.ident.name;
|
||||
methods_in_trait.remove(&method_name);
|
||||
check_trait_method(method_name, impl_item_ref.span);
|
||||
}
|
||||
|
||||
for method_name in methods_in_trait {
|
||||
check_trait_method(method_name, item.span);
|
||||
}
|
||||
},
|
||||
None => {
|
||||
for impl_item_ref in (*items).iter().filter(|impl_item_ref| {
|
||||
matches!(impl_item_ref.kind, rustc_hir::AssocItemKind::Fn { .. })
|
||||
}) {
|
||||
let method_name = impl_item_ref.ident.name;
|
||||
let impl_span = impl_item_ref.span;
|
||||
if let Some(trait_spans) = existing_name.trait_methods.get(&method_name) {
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
SAME_NAME_METHOD,
|
||||
impl_span,
|
||||
"method's name is same to an existing method in a trait",
|
||||
|diag| {
|
||||
// TODO should we `span_note` on every trait?
|
||||
// iterate on trait_spans?
|
||||
diag.span_note(
|
||||
trait_spans[0],
|
||||
&format!("existing `{}` defined here", method_name),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
existing_name.impl_methods.insert(method_name, impl_span);
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
50
clippy_lints/src/types/box_collection.rs
Normal file
50
clippy_lints/src/types/box_collection.rs
Normal file
|
@ -0,0 +1,50 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use clippy_utils::is_ty_param_diagnostic_item;
|
||||
use rustc_hir::{self as hir, def_id::DefId, QPath};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_span::symbol::sym;
|
||||
|
||||
use super::BOX_COLLECTION;
|
||||
|
||||
pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_>, def_id: DefId) -> bool {
|
||||
if_chain! {
|
||||
if Some(def_id) == cx.tcx.lang_items().owned_box();
|
||||
if let Some(item_type) = get_std_collection(cx, qpath);
|
||||
then {
|
||||
let generic = if item_type == "String" {
|
||||
""
|
||||
} else {
|
||||
"<..>"
|
||||
};
|
||||
span_lint_and_help(
|
||||
cx,
|
||||
BOX_COLLECTION,
|
||||
hir_ty.span,
|
||||
&format!(
|
||||
"you seem to be trying to use `Box<{outer}{generic}>`. Consider using just `{outer}{generic}`",
|
||||
outer=item_type,
|
||||
generic = generic),
|
||||
None,
|
||||
&format!(
|
||||
"`{outer}{generic}` is already on the heap, `Box<{outer}{generic}>` makes an extra allocation",
|
||||
outer=item_type,
|
||||
generic = generic)
|
||||
);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_std_collection(cx: &LateContext<'_>, qpath: &QPath<'_>) -> Option<&'static str> {
|
||||
if is_ty_param_diagnostic_item(cx, qpath, sym::vec_type).is_some() {
|
||||
Some("Vec")
|
||||
} else if is_ty_param_diagnostic_item(cx, qpath, sym::string_type).is_some() {
|
||||
Some("String")
|
||||
} else if is_ty_param_diagnostic_item(cx, qpath, sym::hashmap_type).is_some() {
|
||||
Some("HashMap")
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use clippy_utils::is_ty_param_diagnostic_item;
|
||||
use rustc_hir::{self as hir, def_id::DefId, QPath};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_span::symbol::sym;
|
||||
|
||||
use super::BOX_VEC;
|
||||
|
||||
pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_>, def_id: DefId) -> bool {
|
||||
if Some(def_id) == cx.tcx.lang_items().owned_box()
|
||||
&& is_ty_param_diagnostic_item(cx, qpath, sym::vec_type).is_some()
|
||||
{
|
||||
span_lint_and_help(
|
||||
cx,
|
||||
BOX_VEC,
|
||||
hir_ty.span,
|
||||
"you seem to be trying to use `Box<Vec<T>>`. Consider using just `Vec<T>`",
|
||||
None,
|
||||
"`Vec<T>` is already on the heap, `Box<Vec<T>>` makes an extra allocation",
|
||||
);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
mod borrowed_box;
|
||||
mod box_vec;
|
||||
mod box_collection;
|
||||
mod linked_list;
|
||||
mod option_option;
|
||||
mod rc_buffer;
|
||||
|
@ -21,12 +21,12 @@ use rustc_span::source_map::Span;
|
|||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks for use of `Box<Vec<_>>` anywhere in the code.
|
||||
/// Checks for use of `Box<T>` where T is a collection such as Vec anywhere in the code.
|
||||
/// Check the [Box documentation](https://doc.rust-lang.org/std/boxed/index.html) for more information.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// `Vec` already keeps its contents in a separate area on
|
||||
/// the heap. So if you `Box` it, you just add another level of indirection
|
||||
/// Collections already keeps their contents in a separate area on
|
||||
/// the heap. So if you `Box` them, you just add another level of indirection
|
||||
/// without any benefit whatsoever.
|
||||
///
|
||||
/// ### Example
|
||||
|
@ -43,7 +43,7 @@ declare_clippy_lint! {
|
|||
/// values: Vec<Foo>,
|
||||
/// }
|
||||
/// ```
|
||||
pub BOX_VEC,
|
||||
pub BOX_COLLECTION,
|
||||
perf,
|
||||
"usage of `Box<Vec<T>>`, vector elements are already on the heap"
|
||||
}
|
||||
|
@ -298,7 +298,7 @@ pub struct Types {
|
|||
avoid_breaking_exported_api: bool,
|
||||
}
|
||||
|
||||
impl_lint_pass!(Types => [BOX_VEC, VEC_BOX, OPTION_OPTION, LINKEDLIST, BORROWED_BOX, REDUNDANT_ALLOCATION, RC_BUFFER, RC_MUTEX, TYPE_COMPLEXITY]);
|
||||
impl_lint_pass!(Types => [BOX_COLLECTION, VEC_BOX, OPTION_OPTION, LINKEDLIST, BORROWED_BOX, REDUNDANT_ALLOCATION, RC_BUFFER, RC_MUTEX, TYPE_COMPLEXITY]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for Types {
|
||||
fn check_fn(&mut self, cx: &LateContext<'_>, _: FnKind<'_>, decl: &FnDecl<'_>, _: &Body<'_>, _: Span, id: HirId) {
|
||||
|
@ -447,7 +447,7 @@ impl Types {
|
|||
// in `clippy_lints::utils::conf.rs`
|
||||
|
||||
let mut triggered = false;
|
||||
triggered |= box_vec::check(cx, hir_ty, qpath, def_id);
|
||||
triggered |= box_collection::check(cx, hir_ty, qpath, def_id);
|
||||
triggered |= redundant_allocation::check(cx, hir_ty, qpath, def_id);
|
||||
triggered |= rc_buffer::check(cx, hir_ty, qpath, def_id);
|
||||
triggered |= vec_box::check(cx, hir_ty, qpath, def_id, self.vec_box_size_threshold);
|
||||
|
|
|
@ -15,6 +15,14 @@ pub struct Rename {
|
|||
pub rename: String,
|
||||
}
|
||||
|
||||
/// A single disallowed method, used by the `DISALLOWED_METHOD` lint.
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum DisallowedMethod {
|
||||
Simple(String),
|
||||
WithReason { path: String, reason: Option<String> },
|
||||
}
|
||||
|
||||
/// Conf with parse errors
|
||||
#[derive(Default)]
|
||||
pub struct TryConf {
|
||||
|
@ -128,7 +136,7 @@ macro_rules! define_Conf {
|
|||
}
|
||||
|
||||
define_Conf! {
|
||||
/// Lint: ENUM_VARIANT_NAMES, LARGE_TYPES_PASSED_BY_VALUE, TRIVIALLY_COPY_PASS_BY_REF, UNNECESSARY_WRAPS, UPPER_CASE_ACRONYMS, WRONG_SELF_CONVENTION, BOX_VEC, REDUNDANT_ALLOCATION, RC_BUFFER, VEC_BOX, OPTION_OPTION, LINKEDLIST, RC_MUTEX.
|
||||
/// Lint: ENUM_VARIANT_NAMES, LARGE_TYPES_PASSED_BY_VALUE, TRIVIALLY_COPY_PASS_BY_REF, UNNECESSARY_WRAPS, UPPER_CASE_ACRONYMS, WRONG_SELF_CONVENTION, BOX_COLLECTION, REDUNDANT_ALLOCATION, RC_BUFFER, VEC_BOX, OPTION_OPTION, LINKEDLIST, RC_MUTEX.
|
||||
///
|
||||
/// Suppress lints whenever the suggested change would cause breakage for other crates.
|
||||
(avoid_breaking_exported_api: bool = true),
|
||||
|
@ -243,7 +251,7 @@ define_Conf! {
|
|||
/// Lint: DISALLOWED_METHOD.
|
||||
///
|
||||
/// The list of disallowed methods, written as fully qualified paths.
|
||||
(disallowed_methods: Vec<String> = Vec::new()),
|
||||
(disallowed_methods: Vec<crate::utils::conf::DisallowedMethod> = Vec::new()),
|
||||
/// Lint: DISALLOWED_TYPE.
|
||||
///
|
||||
/// The list of disallowed types, written as fully qualified paths.
|
||||
|
|
|
@ -561,9 +561,7 @@ declare_lint_pass!(ProduceIce => [PRODUCE_ICE]);
|
|||
|
||||
impl EarlyLintPass for ProduceIce {
|
||||
fn check_fn(&mut self, _: &EarlyContext<'_>, fn_kind: FnKind<'_>, _: Span, _: NodeId) {
|
||||
if is_trigger_fn(fn_kind) {
|
||||
panic!("Would you like some help with that?");
|
||||
}
|
||||
assert!(!is_trigger_fn(fn_kind), "Would you like some help with that?");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -894,7 +892,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidPaths {
|
|||
}).collect();
|
||||
if !check_path(cx, &path[..]);
|
||||
then {
|
||||
span_lint(cx, CLIPPY_LINTS_INTERNAL, item.span, "invalid path");
|
||||
span_lint(cx, INVALID_PATHS, item.span, "invalid path");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1224,5 +1222,10 @@ fn if_chain_local_span(cx: &LateContext<'_>, local: &Local<'_>, if_chain_span: S
|
|||
let sm = cx.sess().source_map();
|
||||
let span = sm.span_extend_to_prev_str(span, "let", false);
|
||||
let span = sm.span_extend_to_next_char(span, ';', false);
|
||||
Span::new(span.lo() - BytePos(3), span.hi() + BytePos(1), span.ctxt())
|
||||
Span::new(
|
||||
span.lo() - BytePos(3),
|
||||
span.hi() + BytePos(1),
|
||||
span.ctxt(),
|
||||
span.parent(),
|
||||
)
|
||||
}
|
||||
|
|
|
@ -298,6 +298,7 @@ pub struct ClippyConfiguration {
|
|||
default: String,
|
||||
lints: Vec<String>,
|
||||
doc: String,
|
||||
#[allow(dead_code)]
|
||||
deprecation_reason: Option<&'static str>,
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
[package]
|
||||
name = "clippy_utils"
|
||||
version = "0.1.57"
|
||||
edition = "2018"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
|
||||
[dependencies]
|
||||
|
|
|
@ -46,15 +46,12 @@ pub fn eq_pat(l: &Pat, r: &Pat) -> bool {
|
|||
| (Ref(l, Mutability::Not), Ref(r, Mutability::Not))
|
||||
| (Ref(l, Mutability::Mut), Ref(r, Mutability::Mut)) => eq_pat(l, r),
|
||||
(Tuple(l), Tuple(r)) | (Slice(l), Slice(r)) => over(l, r, |l, r| eq_pat(l, r)),
|
||||
(Path(lq, lp), Path(rq, rp)) => both(lq, rq, |l, r| eq_qself(l, r)) && eq_path(lp, rp),
|
||||
(Path(lq, lp), Path(rq, rp)) => both(lq, rq, eq_qself) && eq_path(lp, rp),
|
||||
(TupleStruct(lqself, lp, lfs), TupleStruct(rqself, rp, rfs)) => {
|
||||
eq_maybe_qself(lqself, rqself) && eq_path(lp, rp) && over(lfs, rfs, |l, r| eq_pat(l, r))
|
||||
},
|
||||
(Struct(lqself, lp, lfs, lr), Struct(rqself, rp, rfs, rr)) => {
|
||||
lr == rr
|
||||
&& eq_maybe_qself(lqself, rqself)
|
||||
&& eq_path(lp, rp)
|
||||
&& unordered_over(lfs, rfs, |lf, rf| eq_field_pat(lf, rf))
|
||||
lr == rr && eq_maybe_qself(lqself, rqself) && eq_path(lp, rp) && unordered_over(lfs, rfs, eq_field_pat)
|
||||
},
|
||||
(Or(ls), Or(rs)) => unordered_over(ls, rs, |l, r| eq_pat(l, r)),
|
||||
(MacCall(l), MacCall(r)) => eq_mac_call(l, r),
|
||||
|
@ -76,7 +73,7 @@ pub fn eq_field_pat(l: &PatField, r: &PatField) -> bool {
|
|||
l.is_placeholder == r.is_placeholder
|
||||
&& eq_id(l.ident, r.ident)
|
||||
&& eq_pat(&l.pat, &r.pat)
|
||||
&& over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r))
|
||||
&& over(&l.attrs, &r.attrs, eq_attr)
|
||||
}
|
||||
|
||||
pub fn eq_qself(l: &QSelf, r: &QSelf) -> bool {
|
||||
|
@ -92,7 +89,7 @@ pub fn eq_maybe_qself(l: &Option<QSelf>, r: &Option<QSelf>) -> bool {
|
|||
}
|
||||
|
||||
pub fn eq_path(l: &Path, r: &Path) -> bool {
|
||||
over(&l.segments, &r.segments, |l, r| eq_path_seg(l, r))
|
||||
over(&l.segments, &r.segments, eq_path_seg)
|
||||
}
|
||||
|
||||
pub fn eq_path_seg(l: &PathSegment, r: &PathSegment) -> bool {
|
||||
|
@ -101,9 +98,7 @@ pub fn eq_path_seg(l: &PathSegment, r: &PathSegment) -> bool {
|
|||
|
||||
pub fn eq_generic_args(l: &GenericArgs, r: &GenericArgs) -> bool {
|
||||
match (l, r) {
|
||||
(GenericArgs::AngleBracketed(l), GenericArgs::AngleBracketed(r)) => {
|
||||
over(&l.args, &r.args, |l, r| eq_angle_arg(l, r))
|
||||
},
|
||||
(GenericArgs::AngleBracketed(l), GenericArgs::AngleBracketed(r)) => over(&l.args, &r.args, eq_angle_arg),
|
||||
(GenericArgs::Parenthesized(l), GenericArgs::Parenthesized(r)) => {
|
||||
over(&l.inputs, &r.inputs, |l, r| eq_ty(l, r)) && eq_fn_ret_ty(&l.output, &r.output)
|
||||
},
|
||||
|
@ -142,7 +137,7 @@ pub fn eq_struct_rest(l: &StructRest, r: &StructRest) -> bool {
|
|||
|
||||
pub fn eq_expr(l: &Expr, r: &Expr) -> bool {
|
||||
use ExprKind::*;
|
||||
if !over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r)) {
|
||||
if !over(&l.attrs, &r.attrs, eq_attr) {
|
||||
return false;
|
||||
}
|
||||
match (&l.kind, &r.kind) {
|
||||
|
@ -173,20 +168,20 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool {
|
|||
(Assign(l1, l2, _), Assign(r1, r2, _)) | (Index(l1, l2), Index(r1, r2)) => eq_expr(l1, r1) && eq_expr(l2, r2),
|
||||
(AssignOp(lo, lp, lv), AssignOp(ro, rp, rv)) => lo.node == ro.node && eq_expr(lp, rp) && eq_expr(lv, rv),
|
||||
(Field(lp, lf), Field(rp, rf)) => eq_id(*lf, *rf) && eq_expr(lp, rp),
|
||||
(Match(ls, la), Match(rs, ra)) => eq_expr(ls, rs) && over(la, ra, |l, r| eq_arm(l, r)),
|
||||
(Match(ls, la), Match(rs, ra)) => eq_expr(ls, rs) && over(la, ra, eq_arm),
|
||||
(Closure(lc, la, lm, lf, lb, _), Closure(rc, ra, rm, rf, rb, _)) => {
|
||||
lc == rc && la.is_async() == ra.is_async() && lm == rm && eq_fn_decl(lf, rf) && eq_expr(lb, rb)
|
||||
},
|
||||
(Async(lc, _, lb), Async(rc, _, rb)) => lc == rc && eq_block(lb, rb),
|
||||
(Range(lf, lt, ll), Range(rf, rt, rl)) => ll == rl && eq_expr_opt(lf, rf) && eq_expr_opt(lt, rt),
|
||||
(AddrOf(lbk, lm, le), AddrOf(rbk, rm, re)) => lbk == rbk && lm == rm && eq_expr(le, re),
|
||||
(Path(lq, lp), Path(rq, rp)) => both(lq, rq, |l, r| eq_qself(l, r)) && eq_path(lp, rp),
|
||||
(Path(lq, lp), Path(rq, rp)) => both(lq, rq, eq_qself) && eq_path(lp, rp),
|
||||
(MacCall(l), MacCall(r)) => eq_mac_call(l, r),
|
||||
(Struct(lse), Struct(rse)) => {
|
||||
eq_maybe_qself(&lse.qself, &rse.qself)
|
||||
&& eq_path(&lse.path, &rse.path)
|
||||
&& eq_struct_rest(&lse.rest, &rse.rest)
|
||||
&& unordered_over(&lse.fields, &rse.fields, |l, r| eq_field(l, r))
|
||||
&& unordered_over(&lse.fields, &rse.fields, eq_field)
|
||||
},
|
||||
_ => false,
|
||||
}
|
||||
|
@ -196,7 +191,7 @@ pub fn eq_field(l: &ExprField, r: &ExprField) -> bool {
|
|||
l.is_placeholder == r.is_placeholder
|
||||
&& eq_id(l.ident, r.ident)
|
||||
&& eq_expr(&l.expr, &r.expr)
|
||||
&& over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r))
|
||||
&& over(&l.attrs, &r.attrs, eq_attr)
|
||||
}
|
||||
|
||||
pub fn eq_arm(l: &Arm, r: &Arm) -> bool {
|
||||
|
@ -204,7 +199,7 @@ pub fn eq_arm(l: &Arm, r: &Arm) -> bool {
|
|||
&& eq_pat(&l.pat, &r.pat)
|
||||
&& eq_expr(&l.body, &r.body)
|
||||
&& eq_expr_opt(&l.guard, &r.guard)
|
||||
&& over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r))
|
||||
&& over(&l.attrs, &r.attrs, eq_attr)
|
||||
}
|
||||
|
||||
pub fn eq_label(l: &Option<Label>, r: &Option<Label>) -> bool {
|
||||
|
@ -212,7 +207,7 @@ pub fn eq_label(l: &Option<Label>, r: &Option<Label>) -> bool {
|
|||
}
|
||||
|
||||
pub fn eq_block(l: &Block, r: &Block) -> bool {
|
||||
l.rules == r.rules && over(&l.stmts, &r.stmts, |l, r| eq_stmt(l, r))
|
||||
l.rules == r.rules && over(&l.stmts, &r.stmts, eq_stmt)
|
||||
}
|
||||
|
||||
pub fn eq_stmt(l: &Stmt, r: &Stmt) -> bool {
|
||||
|
@ -222,13 +217,13 @@ pub fn eq_stmt(l: &Stmt, r: &Stmt) -> bool {
|
|||
eq_pat(&l.pat, &r.pat)
|
||||
&& both(&l.ty, &r.ty, |l, r| eq_ty(l, r))
|
||||
&& eq_local_kind(&l.kind, &r.kind)
|
||||
&& over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r))
|
||||
&& over(&l.attrs, &r.attrs, eq_attr)
|
||||
},
|
||||
(Item(l), Item(r)) => eq_item(l, r, eq_item_kind),
|
||||
(Expr(l), Expr(r)) | (Semi(l), Semi(r)) => eq_expr(l, r),
|
||||
(Empty, Empty) => true,
|
||||
(MacCall(l), MacCall(r)) => {
|
||||
l.style == r.style && eq_mac_call(&l.mac, &r.mac) && over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r))
|
||||
l.style == r.style && eq_mac_call(&l.mac, &r.mac) && over(&l.attrs, &r.attrs, eq_attr)
|
||||
},
|
||||
_ => false,
|
||||
}
|
||||
|
@ -245,10 +240,7 @@ pub fn eq_local_kind(l: &LocalKind, r: &LocalKind) -> bool {
|
|||
}
|
||||
|
||||
pub fn eq_item<K>(l: &Item<K>, r: &Item<K>, mut eq_kind: impl FnMut(&K, &K) -> bool) -> bool {
|
||||
eq_id(l.ident, r.ident)
|
||||
&& over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r))
|
||||
&& eq_vis(&l.vis, &r.vis)
|
||||
&& eq_kind(&l.kind, &r.kind)
|
||||
eq_id(l.ident, r.ident) && over(&l.attrs, &r.attrs, eq_attr) && eq_vis(&l.vis, &r.vis) && eq_kind(&l.kind, &r.kind)
|
||||
}
|
||||
|
||||
pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
|
||||
|
@ -272,18 +264,15 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
|
|||
}
|
||||
},
|
||||
(ForeignMod(l), ForeignMod(r)) => {
|
||||
both(&l.abi, &r.abi, |l, r| eq_str_lit(l, r))
|
||||
&& over(&l.items, &r.items, |l, r| eq_item(l, r, eq_foreign_item_kind))
|
||||
both(&l.abi, &r.abi, eq_str_lit) && over(&l.items, &r.items, |l, r| eq_item(l, r, eq_foreign_item_kind))
|
||||
},
|
||||
(TyAlias(box TyAliasKind(ld, lg, lb, lt)), TyAlias(box TyAliasKind(rd, rg, rb, rt))) => {
|
||||
eq_defaultness(*ld, *rd)
|
||||
&& eq_generics(lg, rg)
|
||||
&& over(lb, rb, |l, r| eq_generic_bound(l, r))
|
||||
&& over(lb, rb, eq_generic_bound)
|
||||
&& both(lt, rt, |l, r| eq_ty(l, r))
|
||||
},
|
||||
(Enum(le, lg), Enum(re, rg)) => {
|
||||
over(&le.variants, &re.variants, |l, r| eq_variant(l, r)) && eq_generics(lg, rg)
|
||||
},
|
||||
(Enum(le, lg), Enum(re, rg)) => over(&le.variants, &re.variants, eq_variant) && eq_generics(lg, rg),
|
||||
(Struct(lv, lg), Struct(rv, rg)) | (Union(lv, lg), Union(rv, rg)) => {
|
||||
eq_variant_data(lv, rv) && eq_generics(lg, rg)
|
||||
},
|
||||
|
@ -291,10 +280,10 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
|
|||
la == ra
|
||||
&& matches!(lu, Unsafe::No) == matches!(ru, Unsafe::No)
|
||||
&& eq_generics(lg, rg)
|
||||
&& over(lb, rb, |l, r| eq_generic_bound(l, r))
|
||||
&& over(lb, rb, eq_generic_bound)
|
||||
&& over(li, ri, |l, r| eq_item(l, r, eq_assoc_item_kind))
|
||||
},
|
||||
(TraitAlias(lg, lb), TraitAlias(rg, rb)) => eq_generics(lg, rg) && over(lb, rb, |l, r| eq_generic_bound(l, r)),
|
||||
(TraitAlias(lg, lb), TraitAlias(rg, rb)) => eq_generics(lg, rg) && over(lb, rb, eq_generic_bound),
|
||||
(
|
||||
Impl(box ImplKind {
|
||||
unsafety: lu,
|
||||
|
@ -342,7 +331,7 @@ pub fn eq_foreign_item_kind(l: &ForeignItemKind, r: &ForeignItemKind) -> bool {
|
|||
(TyAlias(box TyAliasKind(ld, lg, lb, lt)), TyAlias(box TyAliasKind(rd, rg, rb, rt))) => {
|
||||
eq_defaultness(*ld, *rd)
|
||||
&& eq_generics(lg, rg)
|
||||
&& over(lb, rb, |l, r| eq_generic_bound(l, r))
|
||||
&& over(lb, rb, eq_generic_bound)
|
||||
&& both(lt, rt, |l, r| eq_ty(l, r))
|
||||
},
|
||||
(MacCall(l), MacCall(r)) => eq_mac_call(l, r),
|
||||
|
@ -360,7 +349,7 @@ pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool {
|
|||
(TyAlias(box TyAliasKind(ld, lg, lb, lt)), TyAlias(box TyAliasKind(rd, rg, rb, rt))) => {
|
||||
eq_defaultness(*ld, *rd)
|
||||
&& eq_generics(lg, rg)
|
||||
&& over(lb, rb, |l, r| eq_generic_bound(l, r))
|
||||
&& over(lb, rb, eq_generic_bound)
|
||||
&& both(lt, rt, |l, r| eq_ty(l, r))
|
||||
},
|
||||
(MacCall(l), MacCall(r)) => eq_mac_call(l, r),
|
||||
|
@ -370,7 +359,7 @@ pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool {
|
|||
|
||||
pub fn eq_variant(l: &Variant, r: &Variant) -> bool {
|
||||
l.is_placeholder == r.is_placeholder
|
||||
&& over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r))
|
||||
&& over(&l.attrs, &r.attrs, eq_attr)
|
||||
&& eq_vis(&l.vis, &r.vis)
|
||||
&& eq_id(l.ident, r.ident)
|
||||
&& eq_variant_data(&l.data, &r.data)
|
||||
|
@ -381,14 +370,14 @@ pub fn eq_variant_data(l: &VariantData, r: &VariantData) -> bool {
|
|||
use VariantData::*;
|
||||
match (l, r) {
|
||||
(Unit(_), Unit(_)) => true,
|
||||
(Struct(l, _), Struct(r, _)) | (Tuple(l, _), Tuple(r, _)) => over(l, r, |l, r| eq_struct_field(l, r)),
|
||||
(Struct(l, _), Struct(r, _)) | (Tuple(l, _), Tuple(r, _)) => over(l, r, eq_struct_field),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn eq_struct_field(l: &FieldDef, r: &FieldDef) -> bool {
|
||||
l.is_placeholder == r.is_placeholder
|
||||
&& over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r))
|
||||
&& over(&l.attrs, &r.attrs, eq_attr)
|
||||
&& eq_vis(&l.vis, &r.vis)
|
||||
&& both(&l.ident, &r.ident, |l, r| eq_id(*l, *r))
|
||||
&& eq_ty(&l.ty, &r.ty)
|
||||
|
@ -406,7 +395,7 @@ pub fn eq_fn_header(l: &FnHeader, r: &FnHeader) -> bool {
|
|||
}
|
||||
|
||||
pub fn eq_generics(l: &Generics, r: &Generics) -> bool {
|
||||
over(&l.params, &r.params, |l, r| eq_generic_param(l, r))
|
||||
over(&l.params, &r.params, eq_generic_param)
|
||||
&& over(&l.where_clause.predicates, &r.where_clause.predicates, |l, r| {
|
||||
eq_where_predicate(l, r)
|
||||
})
|
||||
|
@ -419,10 +408,10 @@ pub fn eq_where_predicate(l: &WherePredicate, r: &WherePredicate) -> bool {
|
|||
over(&l.bound_generic_params, &r.bound_generic_params, |l, r| {
|
||||
eq_generic_param(l, r)
|
||||
}) && eq_ty(&l.bounded_ty, &r.bounded_ty)
|
||||
&& over(&l.bounds, &r.bounds, |l, r| eq_generic_bound(l, r))
|
||||
&& over(&l.bounds, &r.bounds, eq_generic_bound)
|
||||
},
|
||||
(RegionPredicate(l), RegionPredicate(r)) => {
|
||||
eq_id(l.lifetime.ident, r.lifetime.ident) && over(&l.bounds, &r.bounds, |l, r| eq_generic_bound(l, r))
|
||||
eq_id(l.lifetime.ident, r.lifetime.ident) && over(&l.bounds, &r.bounds, eq_generic_bound)
|
||||
},
|
||||
(EqPredicate(l), EqPredicate(r)) => eq_ty(&l.lhs_ty, &r.lhs_ty) && eq_ty(&l.rhs_ty, &r.rhs_ty),
|
||||
_ => false,
|
||||
|
@ -469,7 +458,7 @@ pub fn eq_fn_decl(l: &FnDecl, r: &FnDecl) -> bool {
|
|||
l.is_placeholder == r.is_placeholder
|
||||
&& eq_pat(&l.pat, &r.pat)
|
||||
&& eq_ty(&l.ty, &r.ty)
|
||||
&& over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r))
|
||||
&& over(&l.attrs, &r.attrs, eq_attr)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -496,13 +485,13 @@ pub fn eq_ty(l: &Ty, r: &Ty) -> bool {
|
|||
(BareFn(l), BareFn(r)) => {
|
||||
l.unsafety == r.unsafety
|
||||
&& eq_ext(&l.ext, &r.ext)
|
||||
&& over(&l.generic_params, &r.generic_params, |l, r| eq_generic_param(l, r))
|
||||
&& over(&l.generic_params, &r.generic_params, eq_generic_param)
|
||||
&& eq_fn_decl(&l.decl, &r.decl)
|
||||
},
|
||||
(Tup(l), Tup(r)) => over(l, r, |l, r| eq_ty(l, r)),
|
||||
(Path(lq, lp), Path(rq, rp)) => both(lq, rq, |l, r| eq_qself(l, r)) && eq_path(lp, rp),
|
||||
(TraitObject(lg, ls), TraitObject(rg, rs)) => ls == rs && over(lg, rg, |l, r| eq_generic_bound(l, r)),
|
||||
(ImplTrait(_, lg), ImplTrait(_, rg)) => over(lg, rg, |l, r| eq_generic_bound(l, r)),
|
||||
(Path(lq, lp), Path(rq, rp)) => both(lq, rq, eq_qself) && eq_path(lp, rp),
|
||||
(TraitObject(lg, ls), TraitObject(rg, rs)) => ls == rs && over(lg, rg, eq_generic_bound),
|
||||
(ImplTrait(_, lg), ImplTrait(_, rg)) => over(lg, rg, eq_generic_bound),
|
||||
(Typeof(l), Typeof(r)) => eq_expr(&l.value, &r.value),
|
||||
(MacCall(l), MacCall(r)) => eq_mac_call(l, r),
|
||||
_ => false,
|
||||
|
@ -533,7 +522,7 @@ pub fn eq_generic_param(l: &GenericParam, r: &GenericParam) -> bool {
|
|||
use GenericParamKind::*;
|
||||
l.is_placeholder == r.is_placeholder
|
||||
&& eq_id(l.ident, r.ident)
|
||||
&& over(&l.bounds, &r.bounds, |l, r| eq_generic_bound(l, r))
|
||||
&& over(&l.bounds, &r.bounds, eq_generic_bound)
|
||||
&& match (&l.kind, &r.kind) {
|
||||
(Lifetime, Lifetime) => true,
|
||||
(Type { default: l }, Type { default: r }) => both(l, r, |l, r| eq_ty(l, r)),
|
||||
|
@ -548,10 +537,10 @@ pub fn eq_generic_param(l: &GenericParam, r: &GenericParam) -> bool {
|
|||
kw_span: _,
|
||||
default: rd,
|
||||
},
|
||||
) => eq_ty(lt, rt) && both(ld, rd, |ld, rd| eq_anon_const(ld, rd)),
|
||||
) => eq_ty(lt, rt) && both(ld, rd, eq_anon_const),
|
||||
_ => false,
|
||||
}
|
||||
&& over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r))
|
||||
&& over(&l.attrs, &r.attrs, eq_attr)
|
||||
}
|
||||
|
||||
pub fn eq_generic_bound(l: &GenericBound, r: &GenericBound) -> bool {
|
||||
|
@ -568,7 +557,7 @@ pub fn eq_assoc_constraint(l: &AssocTyConstraint, r: &AssocTyConstraint) -> bool
|
|||
eq_id(l.ident, r.ident)
|
||||
&& match (&l.kind, &r.kind) {
|
||||
(Equality { ty: l }, Equality { ty: r }) => eq_ty(l, r),
|
||||
(Bound { bounds: l }, Bound { bounds: r }) => over(l, r, |l, r| eq_generic_bound(l, r)),
|
||||
(Bound { bounds: l }, Bound { bounds: r }) => over(l, r, eq_generic_bound),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,10 +27,9 @@ fn identify_some_pure_patterns(expr: &Expr<'_>) -> bool {
|
|||
match expr.kind {
|
||||
ExprKind::Lit(..) | ExprKind::ConstBlock(..) | ExprKind::Path(..) | ExprKind::Field(..) => true,
|
||||
ExprKind::AddrOf(_, _, addr_of_expr) => identify_some_pure_patterns(addr_of_expr),
|
||||
ExprKind::Tup(tup_exprs) => tup_exprs.iter().all(|expr| identify_some_pure_patterns(expr)),
|
||||
ExprKind::Tup(tup_exprs) => tup_exprs.iter().all(identify_some_pure_patterns),
|
||||
ExprKind::Struct(_, fields, expr) => {
|
||||
fields.iter().all(|f| identify_some_pure_patterns(f.expr))
|
||||
&& expr.map_or(true, |e| identify_some_pure_patterns(e))
|
||||
fields.iter().all(|f| identify_some_pure_patterns(f.expr)) && expr.map_or(true, identify_some_pure_patterns)
|
||||
},
|
||||
ExprKind::Call(
|
||||
&Expr {
|
||||
|
@ -45,7 +44,7 @@ fn identify_some_pure_patterns(expr: &Expr<'_>) -> bool {
|
|||
..
|
||||
},
|
||||
args,
|
||||
) => args.iter().all(|expr| identify_some_pure_patterns(expr)),
|
||||
) => args.iter().all(identify_some_pure_patterns),
|
||||
ExprKind::Block(
|
||||
&Block {
|
||||
stmts,
|
||||
|
|
|
@ -602,3 +602,33 @@ pub fn is_from_for_desugar(local: &hir::Local<'_>) -> bool {
|
|||
|
||||
false
|
||||
}
|
||||
|
||||
/// A parsed `panic!` expansion
|
||||
pub struct PanicExpn<'tcx> {
|
||||
/// Span of `panic!(..)`
|
||||
pub call_site: Span,
|
||||
/// Inner `format_args!` expansion
|
||||
pub format_args: FormatArgsExpn<'tcx>,
|
||||
}
|
||||
|
||||
impl PanicExpn<'tcx> {
|
||||
/// Parses an expanded `panic!` invocation
|
||||
pub fn parse(expr: &'tcx Expr<'tcx>) -> Option<Self> {
|
||||
if_chain! {
|
||||
if let ExprKind::Block(block, _) = expr.kind;
|
||||
if let Some(init) = block.expr;
|
||||
if let ExprKind::Call(_, [format_args]) = init.kind;
|
||||
let expn_data = expr.span.ctxt().outer_expn_data();
|
||||
if let ExprKind::AddrOf(_, _, format_args) = format_args.kind;
|
||||
if let Some(format_args) = FormatArgsExpn::parse(format_args);
|
||||
then {
|
||||
Some(PanicExpn {
|
||||
call_site: expn_data.call_site,
|
||||
format_args,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -540,7 +540,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
|
|||
std::mem::discriminant(&b.rules).hash(&mut self.s);
|
||||
}
|
||||
|
||||
#[allow(clippy::many_single_char_names, clippy::too_many_lines)]
|
||||
#[allow(clippy::too_many_lines)]
|
||||
pub fn hash_expr(&mut self, e: &Expr<'_>) {
|
||||
let simple_const = self
|
||||
.maybe_typeck_results
|
||||
|
|
|
@ -68,6 +68,7 @@ pub const IO_WRITE: [&str; 3] = ["std", "io", "Write"];
|
|||
pub const IPADDR_V4: [&str; 5] = ["std", "net", "ip", "IpAddr", "V4"];
|
||||
pub const IPADDR_V6: [&str; 5] = ["std", "net", "ip", "IpAddr", "V6"];
|
||||
pub const ITER_REPEAT: [&str; 5] = ["core", "iter", "sources", "repeat", "repeat"];
|
||||
#[allow(clippy::invalid_paths)] // internal lints do not know about all external crates
|
||||
pub const ITERTOOLS_NEXT_TUPLE: [&str; 3] = ["itertools", "Itertools", "next_tuple"];
|
||||
#[cfg(feature = "internal-lints")]
|
||||
pub const KW_MODULE: [&str; 3] = ["rustc_span", "symbol", "kw"];
|
||||
|
|
|
@ -192,9 +192,8 @@ fn check_rvalue(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, def_id: DefId, rvalue: &Rv
|
|||
))
|
||||
}
|
||||
},
|
||||
Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) => Ok(()),
|
||||
Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) | Rvalue::ShallowInitBox(_, _) => Ok(()),
|
||||
Rvalue::NullaryOp(NullOp::Box, _) => Err((span, "heap allocations are not allowed in const fn".into())),
|
||||
Rvalue::ShallowInitBox(_, _) => Ok(()),
|
||||
Rvalue::UnaryOp(_, operand) => {
|
||||
let ty = operand.ty(body, tcx);
|
||||
if ty.is_integral() || ty.is_bool() {
|
||||
|
|
|
@ -15,6 +15,8 @@ use std::{
|
|||
env, fmt,
|
||||
fs::write,
|
||||
path::{Path, PathBuf},
|
||||
thread,
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use clap::{App, Arg, ArgMatches};
|
||||
|
@ -109,6 +111,22 @@ impl std::fmt::Display for ClippyWarning {
|
|||
}
|
||||
}
|
||||
|
||||
fn get(path: &str) -> Result<ureq::Response, ureq::Error> {
|
||||
const MAX_RETRIES: u8 = 4;
|
||||
let mut retries = 0;
|
||||
loop {
|
||||
match ureq::get(path).call() {
|
||||
Ok(res) => return Ok(res),
|
||||
Err(e) if retries >= MAX_RETRIES => return Err(e),
|
||||
Err(ureq::Error::Transport(e)) => eprintln!("Error: {}", e),
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
eprintln!("retrying in {} seconds...", retries);
|
||||
thread::sleep(Duration::from_secs(retries as u64));
|
||||
retries += 1;
|
||||
}
|
||||
}
|
||||
|
||||
impl CrateSource {
|
||||
/// Makes the sources available on the disk for clippy to check.
|
||||
/// Clones a git repo and checks out the specified commit or downloads a crate from crates.io or
|
||||
|
@ -129,7 +147,7 @@ impl CrateSource {
|
|||
if !krate_file_path.is_file() {
|
||||
// create a file path to download and write the crate data into
|
||||
let mut krate_dest = std::fs::File::create(&krate_file_path).unwrap();
|
||||
let mut krate_req = ureq::get(&url).call().unwrap().into_reader();
|
||||
let mut krate_req = get(&url).unwrap().into_reader();
|
||||
// copy the crate into the file
|
||||
std::io::copy(&mut krate_req, &mut krate_dest).unwrap();
|
||||
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
[toolchain]
|
||||
channel = "nightly-2021-09-08"
|
||||
channel = "nightly-2021-09-28"
|
||||
components = ["llvm-tools-preview", "rustc-dev", "rust-src"]
|
||||
|
|
20
src/main.rs
20
src/main.rs
|
@ -4,7 +4,6 @@
|
|||
|
||||
use rustc_tools_util::VersionInfo;
|
||||
use std::env;
|
||||
use std::ffi::OsString;
|
||||
use std::path::PathBuf;
|
||||
use std::process::{self, Command};
|
||||
|
||||
|
@ -14,7 +13,7 @@ Usage:
|
|||
cargo clippy [options] [--] [<opts>...]
|
||||
|
||||
Common options:
|
||||
--no-deps Run Clippy only on the given crate, without linting the dependencies
|
||||
--no-deps Run Clippy only on the given crate, without linting the dependencies
|
||||
--fix Automatically apply lint suggestions. This flag implies `--no-deps`
|
||||
-h, --help Print this message
|
||||
-V, --version Print version info and exit
|
||||
|
@ -116,22 +115,6 @@ impl ClippyCmd {
|
|||
path
|
||||
}
|
||||
|
||||
fn target_dir() -> Option<(&'static str, OsString)> {
|
||||
env::var_os("CLIPPY_DOGFOOD")
|
||||
.map(|_| {
|
||||
env::var_os("CARGO_MANIFEST_DIR").map_or_else(
|
||||
|| std::ffi::OsString::from("clippy_dogfood"),
|
||||
|d| {
|
||||
std::path::PathBuf::from(d)
|
||||
.join("target")
|
||||
.join("dogfood")
|
||||
.into_os_string()
|
||||
},
|
||||
)
|
||||
})
|
||||
.map(|p| ("CARGO_TARGET_DIR", p))
|
||||
}
|
||||
|
||||
fn into_std_cmd(self) -> Command {
|
||||
let mut cmd = Command::new("cargo");
|
||||
let clippy_args: String = self
|
||||
|
@ -141,7 +124,6 @@ impl ClippyCmd {
|
|||
.collect();
|
||||
|
||||
cmd.env("RUSTC_WORKSPACE_WRAPPER", Self::path())
|
||||
.envs(ClippyCmd::target_dir())
|
||||
.env("CLIPPY_ARGS", clippy_args)
|
||||
.arg(self.cargo_subcommand)
|
||||
.args(&self.args);
|
||||
|
|
|
@ -1,25 +1,3 @@
|
|||
use std::env;
|
||||
use std::lazy::SyncLazy;
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub static CARGO_TARGET_DIR: SyncLazy<PathBuf> = SyncLazy::new(|| match env::var_os("CARGO_TARGET_DIR") {
|
||||
Some(v) => v.into(),
|
||||
None => env::current_dir().unwrap().join("target"),
|
||||
});
|
||||
|
||||
pub static TARGET_LIB: SyncLazy<PathBuf> = SyncLazy::new(|| {
|
||||
if let Some(path) = option_env!("TARGET_LIBS") {
|
||||
path.into()
|
||||
} else {
|
||||
let mut dir = CARGO_TARGET_DIR.clone();
|
||||
if let Some(target) = env::var_os("CARGO_BUILD_TARGET") {
|
||||
dir.push(target);
|
||||
}
|
||||
dir.push(env!("PROFILE"));
|
||||
dir
|
||||
}
|
||||
});
|
||||
|
||||
#[must_use]
|
||||
pub fn is_rustc_test_suite() -> bool {
|
||||
option_env!("RUSTC_TEST_SUITE").is_some()
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
#![feature(test)] // compiletest_rs requires this attribute
|
||||
#![feature(once_cell)]
|
||||
#![cfg_attr(feature = "deny-warnings", deny(warnings))]
|
||||
#![warn(rust_2018_idioms, unused_lifetimes)]
|
||||
|
||||
|
@ -46,14 +45,6 @@ extern crate quote;
|
|||
#[allow(unused_extern_crates)]
|
||||
extern crate syn;
|
||||
|
||||
fn host_lib() -> PathBuf {
|
||||
option_env!("HOST_LIBS").map_or(cargo::CARGO_TARGET_DIR.join(env!("PROFILE")), PathBuf::from)
|
||||
}
|
||||
|
||||
fn clippy_driver_path() -> PathBuf {
|
||||
option_env!("CLIPPY_DRIVER_PATH").map_or(cargo::TARGET_LIB.join("clippy-driver"), PathBuf::from)
|
||||
}
|
||||
|
||||
/// Produces a string with an `--extern` flag for all UI test crate
|
||||
/// dependencies.
|
||||
///
|
||||
|
@ -99,12 +90,14 @@ fn extern_flags() -> String {
|
|||
.copied()
|
||||
.filter(|n| !crates.contains_key(n))
|
||||
.collect();
|
||||
if !not_found.is_empty() {
|
||||
panic!("dependencies not found in depinfo: {:?}", not_found);
|
||||
}
|
||||
assert!(
|
||||
not_found.is_empty(),
|
||||
"dependencies not found in depinfo: {:?}",
|
||||
not_found
|
||||
);
|
||||
crates
|
||||
.into_iter()
|
||||
.map(|(name, path)| format!("--extern {}={} ", name, path))
|
||||
.map(|(name, path)| format!(" --extern {}={}", name, path))
|
||||
.collect()
|
||||
}
|
||||
|
||||
|
@ -120,19 +113,29 @@ fn default_config() -> compiletest::Config {
|
|||
config.run_lib_path = path.clone();
|
||||
config.compile_lib_path = path;
|
||||
}
|
||||
let current_exe_path = std::env::current_exe().unwrap();
|
||||
let deps_path = current_exe_path.parent().unwrap();
|
||||
let profile_path = deps_path.parent().unwrap();
|
||||
|
||||
// Using `-L dependency={}` enforces that external dependencies are added with `--extern`.
|
||||
// This is valuable because a) it allows us to monitor what external dependencies are used
|
||||
// and b) it ensures that conflicting rlibs are resolved properly.
|
||||
let host_libs = option_env!("HOST_LIBS")
|
||||
.map(|p| format!(" -L dependency={}", Path::new(p).join("deps").display()))
|
||||
.unwrap_or_default();
|
||||
config.target_rustcflags = Some(format!(
|
||||
"--emit=metadata -L dependency={} -L dependency={} -Dwarnings -Zui-testing {}",
|
||||
host_lib().join("deps").display(),
|
||||
cargo::TARGET_LIB.join("deps").display(),
|
||||
"--emit=metadata -Dwarnings -Zui-testing -L dependency={}{}{}",
|
||||
deps_path.display(),
|
||||
host_libs,
|
||||
extern_flags(),
|
||||
));
|
||||
|
||||
config.build_base = host_lib().join("test_build_base");
|
||||
config.rustc_path = clippy_driver_path();
|
||||
config.build_base = profile_path.join("test");
|
||||
config.rustc_path = profile_path.join(if cfg!(windows) {
|
||||
"clippy-driver.exe"
|
||||
} else {
|
||||
"clippy-driver"
|
||||
});
|
||||
config
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,12 @@ use std::process::Command;
|
|||
|
||||
mod cargo;
|
||||
|
||||
static CLIPPY_PATH: SyncLazy<PathBuf> = SyncLazy::new(|| cargo::TARGET_LIB.join("cargo-clippy"));
|
||||
static CLIPPY_PATH: SyncLazy<PathBuf> = SyncLazy::new(|| {
|
||||
let mut path = std::env::current_exe().unwrap();
|
||||
assert!(path.pop()); // deps
|
||||
path.set_file_name("cargo-clippy");
|
||||
path
|
||||
});
|
||||
|
||||
#[test]
|
||||
fn dogfood_clippy() {
|
||||
|
@ -28,7 +33,6 @@ fn dogfood_clippy() {
|
|||
let mut command = Command::new(&*CLIPPY_PATH);
|
||||
command
|
||||
.current_dir(root_dir)
|
||||
.env("CLIPPY_DOGFOOD", "1")
|
||||
.env("CARGO_INCREMENTAL", "0")
|
||||
.arg("clippy")
|
||||
.arg("--all-targets")
|
||||
|
@ -74,7 +78,6 @@ fn test_no_deps_ignores_path_deps_in_workspaces() {
|
|||
// Make sure that with the `--no-deps` argument Clippy does not run on `path_dep`.
|
||||
let output = Command::new(&*CLIPPY_PATH)
|
||||
.current_dir(&cwd)
|
||||
.env("CLIPPY_DOGFOOD", "1")
|
||||
.env("CARGO_INCREMENTAL", "0")
|
||||
.arg("clippy")
|
||||
.args(&["-p", "subcrate"])
|
||||
|
@ -94,7 +97,6 @@ fn test_no_deps_ignores_path_deps_in_workspaces() {
|
|||
// Test that without the `--no-deps` argument, `path_dep` is linted.
|
||||
let output = Command::new(&*CLIPPY_PATH)
|
||||
.current_dir(&cwd)
|
||||
.env("CLIPPY_DOGFOOD", "1")
|
||||
.env("CARGO_INCREMENTAL", "0")
|
||||
.arg("clippy")
|
||||
.args(&["-p", "subcrate"])
|
||||
|
@ -121,7 +123,6 @@ fn test_no_deps_ignores_path_deps_in_workspaces() {
|
|||
let successful_build = || {
|
||||
let output = Command::new(&*CLIPPY_PATH)
|
||||
.current_dir(&cwd)
|
||||
.env("CLIPPY_DOGFOOD", "1")
|
||||
.env("CARGO_INCREMENTAL", "0")
|
||||
.arg("clippy")
|
||||
.args(&["-p", "subcrate"])
|
||||
|
@ -223,7 +224,6 @@ fn run_clippy_for_project(project: &str) {
|
|||
|
||||
command
|
||||
.current_dir(root_dir.join(project))
|
||||
.env("CLIPPY_DOGFOOD", "1")
|
||||
.env("CARGO_INCREMENTAL", "0")
|
||||
.arg("clippy")
|
||||
.arg("--all-targets")
|
||||
|
|
|
@ -74,8 +74,11 @@ fn integration_test() {
|
|||
panic!("incompatible crate versions");
|
||||
} else if stderr.contains("failed to run `rustc` to learn about target-specific information") {
|
||||
panic!("couldn't find librustc_driver, consider setting `LD_LIBRARY_PATH`");
|
||||
} else if stderr.contains("toolchain") && stderr.contains("is not installed") {
|
||||
panic!("missing required toolchain");
|
||||
} else {
|
||||
assert!(
|
||||
!stderr.contains("toolchain") || !stderr.contains("is not installed"),
|
||||
"missing required toolchain"
|
||||
);
|
||||
}
|
||||
|
||||
match output.status.code() {
|
||||
|
|
|
@ -4,7 +4,7 @@ error: invalid path
|
|||
LL | pub const BAD_CRATE_PATH: [&str; 2] = ["bad", "path"];
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `-D clippy::clippy-lints-internal` implied by `-D warnings`
|
||||
= note: `-D clippy::invalid-paths` implied by `-D warnings`
|
||||
|
||||
error: invalid path
|
||||
--> $DIR/invalid_paths.rs:20:5
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
disallowed-methods = [
|
||||
# just a string is shorthand for path only
|
||||
"std::iter::Iterator::sum",
|
||||
"regex::Regex::is_match",
|
||||
"regex::Regex::new"
|
||||
# can give path and reason with an inline table
|
||||
{ path = "regex::Regex::is_match", reason = "no matching allowed" },
|
||||
# can use an inline table but omit reason
|
||||
{ path = "regex::Regex::new" },
|
||||
]
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
error: use of a disallowed method `regex::re_unicode::Regex::new`
|
||||
error: use of a disallowed method `regex::Regex::new`
|
||||
--> $DIR/conf_disallowed_method.rs:7:14
|
||||
|
|
||||
LL | let re = Regex::new(r"ab.*c").unwrap();
|
||||
|
@ -6,13 +6,15 @@ LL | let re = Regex::new(r"ab.*c").unwrap();
|
|||
|
|
||||
= note: `-D clippy::disallowed-method` implied by `-D warnings`
|
||||
|
||||
error: use of a disallowed method `regex::re_unicode::Regex::is_match`
|
||||
error: use of a disallowed method `regex::Regex::is_match`
|
||||
--> $DIR/conf_disallowed_method.rs:8:5
|
||||
|
|
||||
LL | re.is_match("abc");
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: no matching allowed (from clippy.toml)
|
||||
|
||||
error: use of a disallowed method `core::iter::traits::iterator::Iterator::sum`
|
||||
error: use of a disallowed method `std::iter::Iterator::sum`
|
||||
--> $DIR/conf_disallowed_method.rs:11:5
|
||||
|
|
||||
LL | a.iter().sum::<i32>();
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
// normalize-stderr-test "\(limit: \d+ byte\)" -> "(limit: N byte)"
|
||||
|
||||
#![deny(clippy::trivially_copy_pass_by_ref)]
|
||||
#![allow(clippy::many_single_char_names)]
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
struct Foo(u8);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
|
||||
--> $DIR/test.rs:15:11
|
||||
--> $DIR/test.rs:14:11
|
||||
|
|
||||
LL | fn bad(x: &u16, y: &Foo) {}
|
||||
| ^^^^ help: consider passing by value instead: `u16`
|
||||
|
@ -11,7 +11,7 @@ LL | #![deny(clippy::trivially_copy_pass_by_ref)]
|
|||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
|
||||
--> $DIR/test.rs:15:20
|
||||
--> $DIR/test.rs:14:20
|
||||
|
|
||||
LL | fn bad(x: &u16, y: &Foo) {}
|
||||
| ^^^^ help: consider passing by value instead: `Foo`
|
||||
|
|
75
tests/ui/auxiliary/proc_macro_suspicious_else_formatting.rs
Normal file
75
tests/ui/auxiliary/proc_macro_suspicious_else_formatting.rs
Normal file
|
@ -0,0 +1,75 @@
|
|||
// compile-flags: --emit=link
|
||||
// no-prefer-dynamic
|
||||
|
||||
#![crate_type = "proc-macro"]
|
||||
|
||||
extern crate proc_macro;
|
||||
use proc_macro::{token_stream, Delimiter, Group, Ident, Span, TokenStream, TokenTree};
|
||||
use std::iter::FromIterator;
|
||||
|
||||
fn read_ident(iter: &mut token_stream::IntoIter) -> Ident {
|
||||
match iter.next() {
|
||||
Some(TokenTree::Ident(i)) => i,
|
||||
_ => panic!("expected ident"),
|
||||
}
|
||||
}
|
||||
|
||||
#[proc_macro_derive(DeriveBadSpan)]
|
||||
pub fn derive_bad_span(input: TokenStream) -> TokenStream {
|
||||
let mut input = input.into_iter();
|
||||
assert_eq!(read_ident(&mut input).to_string(), "struct");
|
||||
let ident = read_ident(&mut input);
|
||||
let mut tys = match input.next() {
|
||||
Some(TokenTree::Group(g)) if g.delimiter() == Delimiter::Parenthesis => g.stream().into_iter(),
|
||||
_ => panic!(),
|
||||
};
|
||||
let field1 = read_ident(&mut tys);
|
||||
tys.next();
|
||||
let field2 = read_ident(&mut tys);
|
||||
|
||||
<TokenStream as FromIterator<TokenTree>>::from_iter(
|
||||
[
|
||||
Ident::new("impl", Span::call_site()).into(),
|
||||
ident.into(),
|
||||
Group::new(
|
||||
Delimiter::Brace,
|
||||
<TokenStream as FromIterator<TokenTree>>::from_iter(
|
||||
[
|
||||
Ident::new("fn", Span::call_site()).into(),
|
||||
Ident::new("_foo", Span::call_site()).into(),
|
||||
Group::new(Delimiter::Parenthesis, TokenStream::new()).into(),
|
||||
Group::new(
|
||||
Delimiter::Brace,
|
||||
<TokenStream as FromIterator<TokenTree>>::from_iter(
|
||||
[
|
||||
Ident::new("if", field1.span()).into(),
|
||||
Ident::new("true", field1.span()).into(),
|
||||
{
|
||||
let mut group = Group::new(Delimiter::Brace, TokenStream::new());
|
||||
group.set_span(field1.span());
|
||||
group.into()
|
||||
},
|
||||
Ident::new("if", field2.span()).into(),
|
||||
Ident::new("true", field2.span()).into(),
|
||||
{
|
||||
let mut group = Group::new(Delimiter::Brace, TokenStream::new());
|
||||
group.set_span(field2.span());
|
||||
group.into()
|
||||
},
|
||||
]
|
||||
.iter()
|
||||
.cloned(),
|
||||
),
|
||||
)
|
||||
.into(),
|
||||
]
|
||||
.iter()
|
||||
.cloned(),
|
||||
),
|
||||
)
|
||||
.into(),
|
||||
]
|
||||
.iter()
|
||||
.cloned(),
|
||||
)
|
||||
}
|
|
@ -6,6 +6,8 @@
|
|||
unused
|
||||
)]
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
macro_rules! boxit {
|
||||
($init:expr, $x:ty) => {
|
||||
let _: Box<$x> = Box::new($init);
|
||||
|
@ -15,6 +17,7 @@ macro_rules! boxit {
|
|||
fn test_macro() {
|
||||
boxit!(Vec::new(), Vec<u8>);
|
||||
}
|
||||
|
||||
fn test(foo: Box<Vec<bool>>) {}
|
||||
|
||||
fn test2(foo: Box<dyn Fn(Vec<u32>)>) {
|
||||
|
@ -22,6 +25,10 @@ fn test2(foo: Box<dyn Fn(Vec<u32>)>) {
|
|||
foo(vec![1, 2, 3])
|
||||
}
|
||||
|
||||
fn test3(foo: Box<String>) {}
|
||||
|
||||
fn test4(foo: Box<HashMap<String, String>>) {}
|
||||
|
||||
fn test_local_not_linted() {
|
||||
let _: Box<Vec<bool>>;
|
||||
}
|
||||
|
@ -29,6 +36,7 @@ fn test_local_not_linted() {
|
|||
// All of these test should be allowed because they are part of the
|
||||
// public api and `avoid_breaking_exported_api` is `false` by default.
|
||||
pub fn pub_test(foo: Box<Vec<bool>>) {}
|
||||
|
||||
pub fn pub_test_ret() -> Box<Vec<bool>> {
|
||||
Box::new(Vec::new())
|
||||
}
|
27
tests/ui/box_collection.stderr
Normal file
27
tests/ui/box_collection.stderr
Normal file
|
@ -0,0 +1,27 @@
|
|||
error: you seem to be trying to use `Box<Vec<..>>`. Consider using just `Vec<..>`
|
||||
--> $DIR/box_collection.rs:21:14
|
||||
|
|
||||
LL | fn test(foo: Box<Vec<bool>>) {}
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `-D clippy::box-collection` implied by `-D warnings`
|
||||
= help: `Vec<..>` is already on the heap, `Box<Vec<..>>` makes an extra allocation
|
||||
|
||||
error: you seem to be trying to use `Box<String>`. Consider using just `String`
|
||||
--> $DIR/box_collection.rs:28:15
|
||||
|
|
||||
LL | fn test3(foo: Box<String>) {}
|
||||
| ^^^^^^^^^^^
|
||||
|
|
||||
= help: `String` is already on the heap, `Box<String>` makes an extra allocation
|
||||
|
||||
error: you seem to be trying to use `Box<HashMap<..>>`. Consider using just `HashMap<..>`
|
||||
--> $DIR/box_collection.rs:30:15
|
||||
|
|
||||
LL | fn test4(foo: Box<HashMap<String, String>>) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: `HashMap<..>` is already on the heap, `Box<HashMap<..>>` makes an extra allocation
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
error: you seem to be trying to use `Box<Vec<T>>`. Consider using just `Vec<T>`
|
||||
--> $DIR/box_vec.rs:18:14
|
||||
|
|
||||
LL | fn test(foo: Box<Vec<bool>>) {}
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `-D clippy::box-vec` implied by `-D warnings`
|
||||
= help: `Vec<T>` is already on the heap, `Box<Vec<T>>` makes an extra allocation
|
||||
|
||||
error: aborting due to previous error
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
// run-rustfix
|
||||
|
||||
#![allow(unused_imports,dead_code)]
|
||||
#![allow(unused_imports, dead_code)]
|
||||
#![deny(clippy::default_trait_access)]
|
||||
|
||||
use std::default;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// run-rustfix
|
||||
|
||||
#![allow(unused_imports,dead_code)]
|
||||
#![allow(unused_imports, dead_code)]
|
||||
#![deny(clippy::default_trait_access)]
|
||||
|
||||
use std::default;
|
||||
|
|
|
@ -9,7 +9,7 @@ fn get_reference(n: &usize) -> &usize {
|
|||
n
|
||||
}
|
||||
|
||||
#[allow(clippy::many_single_char_names, clippy::double_parens)]
|
||||
#[allow(clippy::double_parens)]
|
||||
#[allow(unused_variables, unused_parens)]
|
||||
fn main() {
|
||||
let a = 10;
|
||||
|
|
|
@ -9,7 +9,7 @@ fn get_reference(n: &usize) -> &usize {
|
|||
n
|
||||
}
|
||||
|
||||
#[allow(clippy::many_single_char_names, clippy::double_parens)]
|
||||
#[allow(clippy::double_parens)]
|
||||
#[allow(unused_variables, unused_parens)]
|
||||
fn main() {
|
||||
let a = 10;
|
||||
|
|
|
@ -167,4 +167,44 @@ impl Default for WithoutSelfParan {
|
|||
}
|
||||
}
|
||||
|
||||
// https://github.com/rust-lang/rust-clippy/issues/7655
|
||||
|
||||
pub struct SpecializedImpl2<T> {
|
||||
v: Vec<T>,
|
||||
}
|
||||
|
||||
impl Default for SpecializedImpl2<String> {
|
||||
fn default() -> Self {
|
||||
Self { v: Vec::new() }
|
||||
}
|
||||
}
|
||||
|
||||
// https://github.com/rust-lang/rust-clippy/issues/7654
|
||||
|
||||
pub struct Color {
|
||||
pub r: u8,
|
||||
pub g: u8,
|
||||
pub b: u8,
|
||||
}
|
||||
|
||||
/// `#000000`
|
||||
impl Default for Color {
|
||||
fn default() -> Self {
|
||||
Color { r: 0, g: 0, b: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Color2 {
|
||||
pub r: u8,
|
||||
pub g: u8,
|
||||
pub b: u8,
|
||||
}
|
||||
|
||||
impl Default for Color2 {
|
||||
/// `#000000`
|
||||
fn default() -> Self {
|
||||
Self { r: 0, g: 0, b: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
#[rustfmt::skip]
|
||||
#[warn(clippy::eq_op)]
|
||||
#[allow(clippy::identity_op, clippy::double_parens, clippy::many_single_char_names)]
|
||||
#[allow(clippy::identity_op, clippy::double_parens)]
|
||||
#[allow(clippy::no_effect, unused_variables, clippy::unnecessary_operation, clippy::short_circuit_statement)]
|
||||
#[allow(clippy::nonminimal_bool)]
|
||||
#[allow(unused)]
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
unused,
|
||||
clippy::no_effect,
|
||||
clippy::redundant_closure_call,
|
||||
clippy::many_single_char_names,
|
||||
clippy::needless_pass_by_value,
|
||||
clippy::option_map_unit_fn
|
||||
)]
|
||||
|
@ -14,7 +13,7 @@
|
|||
clippy::needless_borrow
|
||||
)]
|
||||
|
||||
use std::path::PathBuf;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
macro_rules! mac {
|
||||
() => {
|
||||
|
@ -30,19 +29,18 @@ macro_rules! closure_mac {
|
|||
|
||||
fn main() {
|
||||
let a = Some(1u8).map(foo);
|
||||
meta(foo);
|
||||
let c = Some(1u8).map(|a| {1+2; foo}(a));
|
||||
true.then(|| mac!()); // don't lint function in macro expansion
|
||||
Some(1).map(closure_mac!()); // don't lint closure in macro expansion
|
||||
let _: Option<Vec<u8>> = true.then(std::vec::Vec::new); // special case vec!
|
||||
let d = Some(1u8).map(|a| foo((|b| foo2(b))(a))); //is adjusted?
|
||||
all(&[1, 2, 3], &2, |x, y| below(x, y)); //is adjusted
|
||||
let d = Some(1u8).map(|a| foo(foo2(a))); //is adjusted?
|
||||
all(&[1, 2, 3], &2, below); //is adjusted
|
||||
unsafe {
|
||||
Some(1u8).map(|a| unsafe_fn(a)); // unsafe fn
|
||||
}
|
||||
|
||||
// See #815
|
||||
let e = Some(1u8).map(|a| divergent(a));
|
||||
let e = Some(1u8).map(divergent);
|
||||
let e = Some(1u8).map(generic);
|
||||
let e = Some(1u8).map(generic);
|
||||
// See #515
|
||||
|
@ -90,24 +88,17 @@ impl<'a> std::ops::Deref for TestStruct<'a> {
|
|||
fn test_redundant_closures_containing_method_calls() {
|
||||
let i = 10;
|
||||
let e = Some(TestStruct { some_ref: &i }).map(TestStruct::foo);
|
||||
let e = Some(TestStruct { some_ref: &i }).map(TestStruct::foo);
|
||||
let e = Some(TestStruct { some_ref: &i }).map(TestTrait::trait_foo);
|
||||
let e = Some(TestStruct { some_ref: &i }).map(|a| a.trait_foo_ref());
|
||||
let e = Some(TestStruct { some_ref: &i }).map(TestTrait::trait_foo);
|
||||
let e = Some(&mut vec![1, 2, 3]).map(std::vec::Vec::clear);
|
||||
let e = Some(&mut vec![1, 2, 3]).map(std::vec::Vec::clear);
|
||||
unsafe {
|
||||
let e = Some(TestStruct { some_ref: &i }).map(|a| a.foo_unsafe());
|
||||
}
|
||||
let e = Some("str").map(std::string::ToString::to_string);
|
||||
let e = Some("str").map(str::to_string);
|
||||
let e = Some('a').map(char::to_uppercase);
|
||||
let e = Some('a').map(char::to_uppercase);
|
||||
let e: std::vec::Vec<usize> = vec!['a', 'b', 'c'].iter().map(|c| c.len_utf8()).collect();
|
||||
let e: std::vec::Vec<char> = vec!['a', 'b', 'c'].iter().map(char::to_ascii_uppercase).collect();
|
||||
let e: std::vec::Vec<char> = vec!['a', 'b', 'c'].iter().map(char::to_ascii_uppercase).collect();
|
||||
let p = Some(PathBuf::new());
|
||||
let e = p.as_ref().and_then(|s| s.to_str());
|
||||
let e = Some(PathBuf::new()).as_ref().and_then(|s| s.to_str());
|
||||
let c = Some(TestStruct { some_ref: &i })
|
||||
.as_ref()
|
||||
.map(|c| c.to_ascii_uppercase());
|
||||
|
@ -119,10 +110,6 @@ fn test_redundant_closures_containing_method_calls() {
|
|||
t.iter().filter(|x| x.trait_foo_ref());
|
||||
t.iter().map(|x| x.trait_foo_ref());
|
||||
}
|
||||
|
||||
let mut some = Some(|x| x * x);
|
||||
let arr = [Ok(1), Err(2)];
|
||||
let _: Vec<_> = arr.iter().map(|x| x.map_err(|e| some.take().unwrap()(e))).collect();
|
||||
}
|
||||
|
||||
struct Thunk<T>(Box<dyn FnMut() -> T>);
|
||||
|
@ -145,13 +132,6 @@ fn foobar() {
|
|||
thunk.unwrap()
|
||||
}
|
||||
|
||||
fn meta<F>(f: F)
|
||||
where
|
||||
F: Fn(u8),
|
||||
{
|
||||
f(1u8)
|
||||
}
|
||||
|
||||
fn foo(_: u8) {}
|
||||
|
||||
fn foo2(_: u8) -> u8 {
|
||||
|
@ -180,7 +160,7 @@ fn generic<T>(_: T) -> u8 {
|
|||
}
|
||||
|
||||
fn passes_fn_mut(mut x: Box<dyn FnMut()>) {
|
||||
requires_fn_once(|| x());
|
||||
requires_fn_once(x);
|
||||
}
|
||||
fn requires_fn_once<T: FnOnce()>(_: T) {}
|
||||
|
||||
|
@ -236,3 +216,35 @@ fn mutable_closure_in_loop() {
|
|||
Some(1).map(&mut closure);
|
||||
}
|
||||
}
|
||||
|
||||
fn late_bound_lifetimes() {
|
||||
fn take_asref_path<P: AsRef<Path>>(path: P) {}
|
||||
|
||||
fn map_str<F>(thunk: F)
|
||||
where
|
||||
F: FnOnce(&str),
|
||||
{
|
||||
}
|
||||
|
||||
fn map_str_to_path<F>(thunk: F)
|
||||
where
|
||||
F: FnOnce(&str) -> &Path,
|
||||
{
|
||||
}
|
||||
map_str(|s| take_asref_path(s));
|
||||
map_str_to_path(std::convert::AsRef::as_ref);
|
||||
}
|
||||
|
||||
mod type_param_bound {
|
||||
trait Trait {
|
||||
fn fun();
|
||||
}
|
||||
|
||||
fn take<T: 'static>(_: T) {}
|
||||
|
||||
fn test<X: Trait>() {
|
||||
// don't lint, but it's questionable that rust requires a cast
|
||||
take(|| X::fun());
|
||||
take(X::fun as fn());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
unused,
|
||||
clippy::no_effect,
|
||||
clippy::redundant_closure_call,
|
||||
clippy::many_single_char_names,
|
||||
clippy::needless_pass_by_value,
|
||||
clippy::option_map_unit_fn
|
||||
)]
|
||||
|
@ -14,7 +13,7 @@
|
|||
clippy::needless_borrow
|
||||
)]
|
||||
|
||||
use std::path::PathBuf;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
macro_rules! mac {
|
||||
() => {
|
||||
|
@ -30,7 +29,6 @@ macro_rules! closure_mac {
|
|||
|
||||
fn main() {
|
||||
let a = Some(1u8).map(|a| foo(a));
|
||||
meta(|a| foo(a));
|
||||
let c = Some(1u8).map(|a| {1+2; foo}(a));
|
||||
true.then(|| mac!()); // don't lint function in macro expansion
|
||||
Some(1).map(closure_mac!()); // don't lint closure in macro expansion
|
||||
|
@ -90,24 +88,17 @@ impl<'a> std::ops::Deref for TestStruct<'a> {
|
|||
fn test_redundant_closures_containing_method_calls() {
|
||||
let i = 10;
|
||||
let e = Some(TestStruct { some_ref: &i }).map(|a| a.foo());
|
||||
let e = Some(TestStruct { some_ref: &i }).map(TestStruct::foo);
|
||||
let e = Some(TestStruct { some_ref: &i }).map(|a| a.trait_foo());
|
||||
let e = Some(TestStruct { some_ref: &i }).map(|a| a.trait_foo_ref());
|
||||
let e = Some(TestStruct { some_ref: &i }).map(TestTrait::trait_foo);
|
||||
let e = Some(&mut vec![1, 2, 3]).map(|v| v.clear());
|
||||
let e = Some(&mut vec![1, 2, 3]).map(std::vec::Vec::clear);
|
||||
unsafe {
|
||||
let e = Some(TestStruct { some_ref: &i }).map(|a| a.foo_unsafe());
|
||||
}
|
||||
let e = Some("str").map(|s| s.to_string());
|
||||
let e = Some("str").map(str::to_string);
|
||||
let e = Some('a').map(|s| s.to_uppercase());
|
||||
let e = Some('a').map(char::to_uppercase);
|
||||
let e: std::vec::Vec<usize> = vec!['a', 'b', 'c'].iter().map(|c| c.len_utf8()).collect();
|
||||
let e: std::vec::Vec<char> = vec!['a', 'b', 'c'].iter().map(|c| c.to_ascii_uppercase()).collect();
|
||||
let e: std::vec::Vec<char> = vec!['a', 'b', 'c'].iter().map(char::to_ascii_uppercase).collect();
|
||||
let p = Some(PathBuf::new());
|
||||
let e = p.as_ref().and_then(|s| s.to_str());
|
||||
let e = Some(PathBuf::new()).as_ref().and_then(|s| s.to_str());
|
||||
let c = Some(TestStruct { some_ref: &i })
|
||||
.as_ref()
|
||||
.map(|c| c.to_ascii_uppercase());
|
||||
|
@ -119,10 +110,6 @@ fn test_redundant_closures_containing_method_calls() {
|
|||
t.iter().filter(|x| x.trait_foo_ref());
|
||||
t.iter().map(|x| x.trait_foo_ref());
|
||||
}
|
||||
|
||||
let mut some = Some(|x| x * x);
|
||||
let arr = [Ok(1), Err(2)];
|
||||
let _: Vec<_> = arr.iter().map(|x| x.map_err(|e| some.take().unwrap()(e))).collect();
|
||||
}
|
||||
|
||||
struct Thunk<T>(Box<dyn FnMut() -> T>);
|
||||
|
@ -145,13 +132,6 @@ fn foobar() {
|
|||
thunk.unwrap()
|
||||
}
|
||||
|
||||
fn meta<F>(f: F)
|
||||
where
|
||||
F: Fn(u8),
|
||||
{
|
||||
f(1u8)
|
||||
}
|
||||
|
||||
fn foo(_: u8) {}
|
||||
|
||||
fn foo2(_: u8) -> u8 {
|
||||
|
@ -236,3 +216,35 @@ fn mutable_closure_in_loop() {
|
|||
Some(1).map(|n| closure(n));
|
||||
}
|
||||
}
|
||||
|
||||
fn late_bound_lifetimes() {
|
||||
fn take_asref_path<P: AsRef<Path>>(path: P) {}
|
||||
|
||||
fn map_str<F>(thunk: F)
|
||||
where
|
||||
F: FnOnce(&str),
|
||||
{
|
||||
}
|
||||
|
||||
fn map_str_to_path<F>(thunk: F)
|
||||
where
|
||||
F: FnOnce(&str) -> &Path,
|
||||
{
|
||||
}
|
||||
map_str(|s| take_asref_path(s));
|
||||
map_str_to_path(|s| s.as_ref());
|
||||
}
|
||||
|
||||
mod type_param_bound {
|
||||
trait Trait {
|
||||
fn fun();
|
||||
}
|
||||
|
||||
fn take<T: 'static>(_: T) {}
|
||||
|
||||
fn test<X: Trait>() {
|
||||
// don't lint, but it's questionable that rust requires a cast
|
||||
take(|| X::fun());
|
||||
take(X::fun as fn());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
error: redundant closure
|
||||
--> $DIR/eta.rs:32:27
|
||||
--> $DIR/eta.rs:31:27
|
||||
|
|
||||
LL | let a = Some(1u8).map(|a| foo(a));
|
||||
| ^^^^^^^^^^ help: replace the closure with the function itself: `foo`
|
||||
|
@ -7,19 +7,19 @@ LL | let a = Some(1u8).map(|a| foo(a));
|
|||
= note: `-D clippy::redundant-closure` implied by `-D warnings`
|
||||
|
||||
error: redundant closure
|
||||
--> $DIR/eta.rs:33:10
|
||||
|
|
||||
LL | meta(|a| foo(a));
|
||||
| ^^^^^^^^^^ help: replace the closure with the function itself: `foo`
|
||||
|
||||
error: redundant closure
|
||||
--> $DIR/eta.rs:37:40
|
||||
--> $DIR/eta.rs:35:40
|
||||
|
|
||||
LL | let _: Option<Vec<u8>> = true.then(|| vec![]); // special case vec!
|
||||
| ^^^^^^^^^ help: replace the closure with `Vec::new`: `std::vec::Vec::new`
|
||||
|
||||
error: redundant closure
|
||||
--> $DIR/eta.rs:36:35
|
||||
|
|
||||
LL | let d = Some(1u8).map(|a| foo((|b| foo2(b))(a))); //is adjusted?
|
||||
| ^^^^^^^^^^^^^ help: replace the closure with the function itself: `foo2`
|
||||
|
||||
error: this expression borrows a reference (`&u8`) that is immediately dereferenced by the compiler
|
||||
--> $DIR/eta.rs:39:21
|
||||
--> $DIR/eta.rs:37:21
|
||||
|
|
||||
LL | all(&[1, 2, 3], &&2, |x, y| below(x, y)); //is adjusted
|
||||
| ^^^ help: change this to: `&2`
|
||||
|
@ -27,13 +27,25 @@ LL | all(&[1, 2, 3], &&2, |x, y| below(x, y)); //is adjusted
|
|||
= note: `-D clippy::needless-borrow` implied by `-D warnings`
|
||||
|
||||
error: redundant closure
|
||||
--> $DIR/eta.rs:46:27
|
||||
--> $DIR/eta.rs:37:26
|
||||
|
|
||||
LL | all(&[1, 2, 3], &&2, |x, y| below(x, y)); //is adjusted
|
||||
| ^^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `below`
|
||||
|
||||
error: redundant closure
|
||||
--> $DIR/eta.rs:43:27
|
||||
|
|
||||
LL | let e = Some(1u8).map(|a| divergent(a));
|
||||
| ^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `divergent`
|
||||
|
||||
error: redundant closure
|
||||
--> $DIR/eta.rs:44:27
|
||||
|
|
||||
LL | let e = Some(1u8).map(|a| generic(a));
|
||||
| ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `generic`
|
||||
|
||||
error: redundant closure
|
||||
--> $DIR/eta.rs:92:51
|
||||
--> $DIR/eta.rs:90:51
|
||||
|
|
||||
LL | let e = Some(TestStruct { some_ref: &i }).map(|a| a.foo());
|
||||
| ^^^^^^^^^^^ help: replace the closure with the method itself: `TestStruct::foo`
|
||||
|
@ -41,70 +53,82 @@ LL | let e = Some(TestStruct { some_ref: &i }).map(|a| a.foo());
|
|||
= note: `-D clippy::redundant-closure-for-method-calls` implied by `-D warnings`
|
||||
|
||||
error: redundant closure
|
||||
--> $DIR/eta.rs:94:51
|
||||
--> $DIR/eta.rs:91:51
|
||||
|
|
||||
LL | let e = Some(TestStruct { some_ref: &i }).map(|a| a.trait_foo());
|
||||
| ^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `TestTrait::trait_foo`
|
||||
|
||||
error: redundant closure
|
||||
--> $DIR/eta.rs:97:42
|
||||
--> $DIR/eta.rs:93:42
|
||||
|
|
||||
LL | let e = Some(&mut vec![1, 2, 3]).map(|v| v.clear());
|
||||
| ^^^^^^^^^^^^^ help: replace the closure with the method itself: `std::vec::Vec::clear`
|
||||
|
||||
error: redundant closure
|
||||
--> $DIR/eta.rs:102:29
|
||||
--> $DIR/eta.rs:97:29
|
||||
|
|
||||
LL | let e = Some("str").map(|s| s.to_string());
|
||||
| ^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `std::string::ToString::to_string`
|
||||
|
||||
error: redundant closure
|
||||
--> $DIR/eta.rs:104:27
|
||||
--> $DIR/eta.rs:98:27
|
||||
|
|
||||
LL | let e = Some('a').map(|s| s.to_uppercase());
|
||||
| ^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `char::to_uppercase`
|
||||
|
||||
error: redundant closure
|
||||
--> $DIR/eta.rs:107:65
|
||||
--> $DIR/eta.rs:100:65
|
||||
|
|
||||
LL | let e: std::vec::Vec<char> = vec!['a', 'b', 'c'].iter().map(|c| c.to_ascii_uppercase()).collect();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `char::to_ascii_uppercase`
|
||||
|
||||
error: redundant closure
|
||||
--> $DIR/eta.rs:190:27
|
||||
--> $DIR/eta.rs:163:22
|
||||
|
|
||||
LL | requires_fn_once(|| x());
|
||||
| ^^^^^^ help: replace the closure with the function itself: `x`
|
||||
|
||||
error: redundant closure
|
||||
--> $DIR/eta.rs:170:27
|
||||
|
|
||||
LL | let a = Some(1u8).map(|a| foo_ptr(a));
|
||||
| ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `foo_ptr`
|
||||
|
||||
error: redundant closure
|
||||
--> $DIR/eta.rs:195:27
|
||||
--> $DIR/eta.rs:175:27
|
||||
|
|
||||
LL | let a = Some(1u8).map(|a| closure(a));
|
||||
| ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `closure`
|
||||
|
||||
error: redundant closure
|
||||
--> $DIR/eta.rs:227:28
|
||||
--> $DIR/eta.rs:207:28
|
||||
|
|
||||
LL | x.into_iter().for_each(|x| add_to_res(x));
|
||||
| ^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut add_to_res`
|
||||
|
||||
error: redundant closure
|
||||
--> $DIR/eta.rs:228:28
|
||||
--> $DIR/eta.rs:208:28
|
||||
|
|
||||
LL | y.into_iter().for_each(|x| add_to_res(x));
|
||||
| ^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut add_to_res`
|
||||
|
||||
error: redundant closure
|
||||
--> $DIR/eta.rs:229:28
|
||||
--> $DIR/eta.rs:209:28
|
||||
|
|
||||
LL | z.into_iter().for_each(|x| add_to_res(x));
|
||||
| ^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `add_to_res`
|
||||
|
||||
error: redundant closure
|
||||
--> $DIR/eta.rs:236:21
|
||||
--> $DIR/eta.rs:216:21
|
||||
|
|
||||
LL | Some(1).map(|n| closure(n));
|
||||
| ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut closure`
|
||||
|
||||
error: aborting due to 17 previous errors
|
||||
error: redundant closure
|
||||
--> $DIR/eta.rs:235:21
|
||||
|
|
||||
LL | map_str_to_path(|s| s.as_ref());
|
||||
| ^^^^^^^^^^^^^^ help: replace the closure with the method itself: `std::convert::AsRef::as_ref`
|
||||
|
||||
error: aborting due to 21 previous errors
|
||||
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
#[allow(
|
||||
unused_assignments,
|
||||
unused_variables,
|
||||
clippy::many_single_char_names,
|
||||
clippy::no_effect,
|
||||
dead_code,
|
||||
clippy::blacklisted_name
|
||||
|
|
|
@ -1,48 +1,48 @@
|
|||
error: unsequenced read of `x`
|
||||
--> $DIR/eval_order_dependence.rs:17:9
|
||||
--> $DIR/eval_order_dependence.rs:16:9
|
||||
|
|
||||
LL | } + x;
|
||||
| ^
|
||||
|
|
||||
= note: `-D clippy::eval-order-dependence` implied by `-D warnings`
|
||||
note: whether read occurs before this write depends on evaluation order
|
||||
--> $DIR/eval_order_dependence.rs:15:9
|
||||
--> $DIR/eval_order_dependence.rs:14:9
|
||||
|
|
||||
LL | x = 1;
|
||||
| ^^^^^
|
||||
|
||||
error: unsequenced read of `x`
|
||||
--> $DIR/eval_order_dependence.rs:20:5
|
||||
--> $DIR/eval_order_dependence.rs:19:5
|
||||
|
|
||||
LL | x += {
|
||||
| ^
|
||||
|
|
||||
note: whether read occurs before this write depends on evaluation order
|
||||
--> $DIR/eval_order_dependence.rs:21:9
|
||||
--> $DIR/eval_order_dependence.rs:20:9
|
||||
|
|
||||
LL | x = 20;
|
||||
| ^^^^^^
|
||||
|
||||
error: unsequenced read of `x`
|
||||
--> $DIR/eval_order_dependence.rs:33:12
|
||||
--> $DIR/eval_order_dependence.rs:32:12
|
||||
|
|
||||
LL | a: x,
|
||||
| ^
|
||||
|
|
||||
note: whether read occurs before this write depends on evaluation order
|
||||
--> $DIR/eval_order_dependence.rs:35:13
|
||||
--> $DIR/eval_order_dependence.rs:34:13
|
||||
|
|
||||
LL | x = 6;
|
||||
| ^^^^^
|
||||
|
||||
error: unsequenced read of `x`
|
||||
--> $DIR/eval_order_dependence.rs:42:9
|
||||
--> $DIR/eval_order_dependence.rs:41:9
|
||||
|
|
||||
LL | x += {
|
||||
| ^
|
||||
|
|
||||
note: whether read occurs before this write depends on evaluation order
|
||||
--> $DIR/eval_order_dependence.rs:43:13
|
||||
--> $DIR/eval_order_dependence.rs:42:13
|
||||
|
|
||||
LL | x = 20;
|
||||
| ^^^^^^
|
||||
|
|
|
@ -17,8 +17,8 @@ fn main() {
|
|||
const BAD32_3: f32 = 0.1;
|
||||
const BAD32_EDGE: f32 = 1.000_001;
|
||||
|
||||
const BAD64_1: f64 = 0.123_456_789_012_345_66_f64;
|
||||
const BAD64_2: f64 = 0.123_456_789_012_345_66;
|
||||
const BAD64_1: f64 = 0.123_456_789_012_345_67f64;
|
||||
const BAD64_2: f64 = 0.123_456_789_012_345_67;
|
||||
const BAD64_3: f64 = 0.1;
|
||||
|
||||
// Literal as param
|
||||
|
@ -37,9 +37,9 @@ fn main() {
|
|||
let bad32_suf: f32 = 1.123_456_8_f32;
|
||||
let bad32_inf = 1.123_456_8_f32;
|
||||
|
||||
let bad64: f64 = 0.123_456_789_012_345_66;
|
||||
let bad64_suf: f64 = 0.123_456_789_012_345_66_f64;
|
||||
let bad64_inf = 0.123_456_789_012_345_66;
|
||||
let bad64: f64 = 0.123_456_789_012_345_67;
|
||||
let bad64_suf: f64 = 0.123_456_789_012_345_67f64;
|
||||
let bad64_inf = 0.123_456_789_012_345_67;
|
||||
|
||||
// Vectors
|
||||
let good_vec32: Vec<f32> = vec![0.123_456];
|
||||
|
|
|
@ -24,18 +24,6 @@ error: float has excessive precision
|
|||
LL | const BAD32_EDGE: f32 = 1.000_000_9;
|
||||
| ^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.000_001`
|
||||
|
||||
error: float has excessive precision
|
||||
--> $DIR/excessive_precision.rs:20:26
|
||||
|
|
||||
LL | const BAD64_1: f64 = 0.123_456_789_012_345_67f64;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_789_012_345_66_f64`
|
||||
|
||||
error: float has excessive precision
|
||||
--> $DIR/excessive_precision.rs:21:26
|
||||
|
|
||||
LL | const BAD64_2: f64 = 0.123_456_789_012_345_67;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_789_012_345_66`
|
||||
|
||||
error: float has excessive precision
|
||||
--> $DIR/excessive_precision.rs:22:26
|
||||
|
|
||||
|
@ -66,24 +54,6 @@ error: float has excessive precision
|
|||
LL | let bad32_inf = 1.123_456_789_f32;
|
||||
| ^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.123_456_8_f32`
|
||||
|
||||
error: float has excessive precision
|
||||
--> $DIR/excessive_precision.rs:40:22
|
||||
|
|
||||
LL | let bad64: f64 = 0.123_456_789_012_345_67;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_789_012_345_66`
|
||||
|
||||
error: float has excessive precision
|
||||
--> $DIR/excessive_precision.rs:41:26
|
||||
|
|
||||
LL | let bad64_suf: f64 = 0.123_456_789_012_345_67f64;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_789_012_345_66_f64`
|
||||
|
||||
error: float has excessive precision
|
||||
--> $DIR/excessive_precision.rs:42:21
|
||||
|
|
||||
LL | let bad64_inf = 0.123_456_789_012_345_67;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `0.123_456_789_012_345_66`
|
||||
|
||||
error: float has excessive precision
|
||||
--> $DIR/excessive_precision.rs:48:36
|
||||
|
|
||||
|
@ -108,5 +78,5 @@ error: float has excessive precision
|
|||
LL | let bad_bige32: f32 = 1.123_456_788_888E-10;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ help: consider changing the type or truncating it to: `1.123_456_8E-10`
|
||||
|
||||
error: aborting due to 18 previous errors
|
||||
error: aborting due to 13 previous errors
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// run-rustfix
|
||||
|
||||
#![allow(unused_variables, clippy::many_single_char_names, clippy::clone_double_ref)]
|
||||
#![allow(unused_variables, clippy::clone_double_ref)]
|
||||
#![warn(clippy::explicit_deref_methods)]
|
||||
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// run-rustfix
|
||||
|
||||
#![allow(unused_variables, clippy::many_single_char_names, clippy::clone_double_ref)]
|
||||
#![allow(unused_variables, clippy::clone_double_ref)]
|
||||
#![warn(clippy::explicit_deref_methods)]
|
||||
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#![deny(clippy::fallible_impl_from)]
|
||||
#![allow(clippy::if_then_panic)]
|
||||
|
||||
// docs example
|
||||
struct Foo(i32);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
error: consider implementing `TryFrom` instead
|
||||
--> $DIR/fallible_impl_from.rs:5:1
|
||||
--> $DIR/fallible_impl_from.rs:6:1
|
||||
|
|
||||
LL | / impl From<String> for Foo {
|
||||
LL | | fn from(s: String) -> Self {
|
||||
|
@ -15,13 +15,13 @@ LL | #![deny(clippy::fallible_impl_from)]
|
|||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
= help: `From` is intended for infallible conversions only. Use `TryFrom` if there's a possibility for the conversion to fail
|
||||
note: potential failure(s)
|
||||
--> $DIR/fallible_impl_from.rs:7:13
|
||||
--> $DIR/fallible_impl_from.rs:8:13
|
||||
|
|
||||
LL | Foo(s.parse().unwrap())
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: consider implementing `TryFrom` instead
|
||||
--> $DIR/fallible_impl_from.rs:26:1
|
||||
--> $DIR/fallible_impl_from.rs:27:1
|
||||
|
|
||||
LL | / impl From<usize> for Invalid {
|
||||
LL | | fn from(i: usize) -> Invalid {
|
||||
|
@ -34,14 +34,14 @@ LL | | }
|
|||
|
|
||||
= help: `From` is intended for infallible conversions only. Use `TryFrom` if there's a possibility for the conversion to fail
|
||||
note: potential failure(s)
|
||||
--> $DIR/fallible_impl_from.rs:29:13
|
||||
--> $DIR/fallible_impl_from.rs:30:13
|
||||
|
|
||||
LL | panic!();
|
||||
| ^^^^^^^^^
|
||||
= note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: consider implementing `TryFrom` instead
|
||||
--> $DIR/fallible_impl_from.rs:35:1
|
||||
--> $DIR/fallible_impl_from.rs:36:1
|
||||
|
|
||||
LL | / impl From<Option<String>> for Invalid {
|
||||
LL | | fn from(s: Option<String>) -> Invalid {
|
||||
|
@ -54,7 +54,7 @@ LL | | }
|
|||
|
|
||||
= help: `From` is intended for infallible conversions only. Use `TryFrom` if there's a possibility for the conversion to fail
|
||||
note: potential failure(s)
|
||||
--> $DIR/fallible_impl_from.rs:37:17
|
||||
--> $DIR/fallible_impl_from.rs:38:17
|
||||
|
|
||||
LL | let s = s.unwrap();
|
||||
| ^^^^^^^^^^
|
||||
|
@ -68,7 +68,7 @@ LL | panic!("{:?}", s);
|
|||
= note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: consider implementing `TryFrom` instead
|
||||
--> $DIR/fallible_impl_from.rs:53:1
|
||||
--> $DIR/fallible_impl_from.rs:54:1
|
||||
|
|
||||
LL | / impl<'a> From<&'a mut <Box<u32> as ProjStrTrait>::ProjString> for Invalid {
|
||||
LL | | fn from(s: &'a mut <Box<u32> as ProjStrTrait>::ProjString) -> Invalid {
|
||||
|
@ -81,7 +81,7 @@ LL | | }
|
|||
|
|
||||
= help: `From` is intended for infallible conversions only. Use `TryFrom` if there's a possibility for the conversion to fail
|
||||
note: potential failure(s)
|
||||
--> $DIR/fallible_impl_from.rs:55:12
|
||||
--> $DIR/fallible_impl_from.rs:56:12
|
||||
|
|
||||
LL | if s.parse::<u32>().ok().unwrap() != 42 {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
|
@ -4,8 +4,7 @@
|
|||
clippy::no_effect,
|
||||
clippy::op_ref,
|
||||
clippy::unnecessary_operation,
|
||||
clippy::cast_lossless,
|
||||
clippy::many_single_char_names
|
||||
clippy::cast_lossless
|
||||
)]
|
||||
|
||||
use std::ops::Add;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
error: strict comparison of `f32` or `f64`
|
||||
--> $DIR/float_cmp.rs:58:5
|
||||
--> $DIR/float_cmp.rs:57:5
|
||||
|
|
||||
LL | ONE as f64 != 2.0;
|
||||
| ^^^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(ONE as f64 - 2.0).abs() > error_margin`
|
||||
|
@ -8,7 +8,7 @@ LL | ONE as f64 != 2.0;
|
|||
= note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
|
||||
|
||||
error: strict comparison of `f32` or `f64`
|
||||
--> $DIR/float_cmp.rs:63:5
|
||||
--> $DIR/float_cmp.rs:62:5
|
||||
|
|
||||
LL | x == 1.0;
|
||||
| ^^^^^^^^ help: consider comparing them within some margin of error: `(x - 1.0).abs() < error_margin`
|
||||
|
@ -16,7 +16,7 @@ LL | x == 1.0;
|
|||
= note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
|
||||
|
||||
error: strict comparison of `f32` or `f64`
|
||||
--> $DIR/float_cmp.rs:66:5
|
||||
--> $DIR/float_cmp.rs:65:5
|
||||
|
|
||||
LL | twice(x) != twice(ONE as f64);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(twice(x) - twice(ONE as f64)).abs() > error_margin`
|
||||
|
@ -24,7 +24,7 @@ LL | twice(x) != twice(ONE as f64);
|
|||
= note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
|
||||
|
||||
error: strict comparison of `f32` or `f64`
|
||||
--> $DIR/float_cmp.rs:86:5
|
||||
--> $DIR/float_cmp.rs:85:5
|
||||
|
|
||||
LL | NON_ZERO_ARRAY[i] == NON_ZERO_ARRAY[j];
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(NON_ZERO_ARRAY[i] - NON_ZERO_ARRAY[j]).abs() < error_margin`
|
||||
|
@ -32,7 +32,7 @@ LL | NON_ZERO_ARRAY[i] == NON_ZERO_ARRAY[j];
|
|||
= note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
|
||||
|
||||
error: strict comparison of `f32` or `f64` arrays
|
||||
--> $DIR/float_cmp.rs:91:5
|
||||
--> $DIR/float_cmp.rs:90:5
|
||||
|
|
||||
LL | a1 == a2;
|
||||
| ^^^^^^^^
|
||||
|
@ -40,7 +40,7 @@ LL | a1 == a2;
|
|||
= note: `f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`
|
||||
|
||||
error: strict comparison of `f32` or `f64`
|
||||
--> $DIR/float_cmp.rs:92:5
|
||||
--> $DIR/float_cmp.rs:91:5
|
||||
|
|
||||
LL | a1[0] == a2[0];
|
||||
| ^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(a1[0] - a2[0]).abs() < error_margin`
|
||||
|
|
|
@ -29,7 +29,7 @@ impl Unrelated {
|
|||
clippy::unnecessary_mut_passed,
|
||||
clippy::similar_names
|
||||
)]
|
||||
#[allow(clippy::many_single_char_names, unused_variables)]
|
||||
#[allow(unused_variables)]
|
||||
fn main() {
|
||||
let mut vec = vec![1, 2, 3, 4];
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ impl Unrelated {
|
|||
clippy::unnecessary_mut_passed,
|
||||
clippy::similar_names
|
||||
)]
|
||||
#[allow(clippy::many_single_char_names, unused_variables)]
|
||||
#[allow(unused_variables)]
|
||||
fn main() {
|
||||
let mut vec = vec![1, 2, 3, 4];
|
||||
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
// run-rustfix
|
||||
|
||||
#![warn(clippy::if_let_some_result)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
fn str_to_int(x: &str) -> i32 {
|
||||
if let Ok(y) = x.parse() { y } else { 0 }
|
||||
}
|
||||
|
||||
fn str_to_int_ok(x: &str) -> i32 {
|
||||
if let Ok(y) = x.parse() { y } else { 0 }
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
fn strange_some_no_else(x: &str) -> i32 {
|
||||
{
|
||||
if let Ok(y) = x . parse() {
|
||||
return y;
|
||||
};
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
fn negative() {
|
||||
while let Some(1) = "".parse().ok() {}
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -1,28 +0,0 @@
|
|||
// run-rustfix
|
||||
|
||||
#![warn(clippy::if_let_some_result)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
fn str_to_int(x: &str) -> i32 {
|
||||
if let Some(y) = x.parse().ok() { y } else { 0 }
|
||||
}
|
||||
|
||||
fn str_to_int_ok(x: &str) -> i32 {
|
||||
if let Ok(y) = x.parse() { y } else { 0 }
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
fn strange_some_no_else(x: &str) -> i32 {
|
||||
{
|
||||
if let Some(y) = x . parse() . ok () {
|
||||
return y;
|
||||
};
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
fn negative() {
|
||||
while let Some(1) = "".parse().ok() {}
|
||||
}
|
||||
|
||||
fn main() {}
|
34
tests/ui/if_then_panic.fixed
Normal file
34
tests/ui/if_then_panic.fixed
Normal file
|
@ -0,0 +1,34 @@
|
|||
// run-rustfix
|
||||
#![warn(clippy::if_then_panic)]
|
||||
|
||||
fn main() {
|
||||
let a = vec![1, 2, 3];
|
||||
let c = Some(2);
|
||||
if !a.is_empty()
|
||||
&& a.len() == 3
|
||||
&& c != None
|
||||
&& !a.is_empty()
|
||||
&& a.len() == 3
|
||||
&& !a.is_empty()
|
||||
&& a.len() == 3
|
||||
&& !a.is_empty()
|
||||
&& a.len() == 3
|
||||
{
|
||||
panic!("qaqaq{:?}", a);
|
||||
}
|
||||
assert!(a.is_empty(), "qaqaq{:?}", a);
|
||||
assert!(a.is_empty(), "qwqwq");
|
||||
if a.len() == 3 {
|
||||
println!("qwq");
|
||||
println!("qwq");
|
||||
println!("qwq");
|
||||
}
|
||||
if let Some(b) = c {
|
||||
panic!("orz {}", b);
|
||||
}
|
||||
if a.len() == 3 {
|
||||
panic!("qaqaq");
|
||||
} else {
|
||||
println!("qwq");
|
||||
}
|
||||
}
|
38
tests/ui/if_then_panic.rs
Normal file
38
tests/ui/if_then_panic.rs
Normal file
|
@ -0,0 +1,38 @@
|
|||
// run-rustfix
|
||||
#![warn(clippy::if_then_panic)]
|
||||
|
||||
fn main() {
|
||||
let a = vec![1, 2, 3];
|
||||
let c = Some(2);
|
||||
if !a.is_empty()
|
||||
&& a.len() == 3
|
||||
&& c != None
|
||||
&& !a.is_empty()
|
||||
&& a.len() == 3
|
||||
&& !a.is_empty()
|
||||
&& a.len() == 3
|
||||
&& !a.is_empty()
|
||||
&& a.len() == 3
|
||||
{
|
||||
panic!("qaqaq{:?}", a);
|
||||
}
|
||||
if !a.is_empty() {
|
||||
panic!("qaqaq{:?}", a);
|
||||
}
|
||||
if !a.is_empty() {
|
||||
panic!("qwqwq");
|
||||
}
|
||||
if a.len() == 3 {
|
||||
println!("qwq");
|
||||
println!("qwq");
|
||||
println!("qwq");
|
||||
}
|
||||
if let Some(b) = c {
|
||||
panic!("orz {}", b);
|
||||
}
|
||||
if a.len() == 3 {
|
||||
panic!("qaqaq");
|
||||
} else {
|
||||
println!("qwq");
|
||||
}
|
||||
}
|
20
tests/ui/if_then_panic.stderr
Normal file
20
tests/ui/if_then_panic.stderr
Normal file
|
@ -0,0 +1,20 @@
|
|||
error: only a `panic!` in `if`-then statement
|
||||
--> $DIR/if_then_panic.rs:19:5
|
||||
|
|
||||
LL | / if !a.is_empty() {
|
||||
LL | | panic!("qaqaq{:?}", a);
|
||||
LL | | }
|
||||
| |_____^ help: try: `assert!(a.is_empty(), "qaqaq{:?}", a);`
|
||||
|
|
||||
= note: `-D clippy::if-then-panic` implied by `-D warnings`
|
||||
|
||||
error: only a `panic!` in `if`-then statement
|
||||
--> $DIR/if_then_panic.rs:22:5
|
||||
|
|
||||
LL | / if !a.is_empty() {
|
||||
LL | | panic!("qwqwq");
|
||||
LL | | }
|
||||
| |_____^ help: try: `assert!(a.is_empty(), "qwqwq");`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
|
@ -16,7 +16,6 @@ fn foob() -> bool {
|
|||
unimplemented!()
|
||||
}
|
||||
|
||||
#[allow(clippy::many_single_char_names)]
|
||||
fn immutable_condition() {
|
||||
// Should warn when all vars mentioned are immutable
|
||||
let y = 0;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
error: variables in the condition are not mutated in the loop body
|
||||
--> $DIR/infinite_loop.rs:23:11
|
||||
--> $DIR/infinite_loop.rs:22:11
|
||||
|
|
||||
LL | while y < 10 {
|
||||
| ^^^^^^
|
||||
|
@ -8,7 +8,7 @@ LL | while y < 10 {
|
|||
= note: this may lead to an infinite or to a never running loop
|
||||
|
||||
error: variables in the condition are not mutated in the loop body
|
||||
--> $DIR/infinite_loop.rs:28:11
|
||||
--> $DIR/infinite_loop.rs:27:11
|
||||
|
|
||||
LL | while y < 10 && x < 3 {
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
@ -16,7 +16,7 @@ LL | while y < 10 && x < 3 {
|
|||
= note: this may lead to an infinite or to a never running loop
|
||||
|
||||
error: variables in the condition are not mutated in the loop body
|
||||
--> $DIR/infinite_loop.rs:35:11
|
||||
--> $DIR/infinite_loop.rs:34:11
|
||||
|
|
||||
LL | while !cond {
|
||||
| ^^^^^
|
||||
|
@ -24,7 +24,7 @@ LL | while !cond {
|
|||
= note: this may lead to an infinite or to a never running loop
|
||||
|
||||
error: variables in the condition are not mutated in the loop body
|
||||
--> $DIR/infinite_loop.rs:79:11
|
||||
--> $DIR/infinite_loop.rs:78:11
|
||||
|
|
||||
LL | while i < 3 {
|
||||
| ^^^^^
|
||||
|
@ -32,7 +32,7 @@ LL | while i < 3 {
|
|||
= note: this may lead to an infinite or to a never running loop
|
||||
|
||||
error: variables in the condition are not mutated in the loop body
|
||||
--> $DIR/infinite_loop.rs:84:11
|
||||
--> $DIR/infinite_loop.rs:83:11
|
||||
|
|
||||
LL | while i < 3 && j > 0 {
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
@ -40,7 +40,7 @@ LL | while i < 3 && j > 0 {
|
|||
= note: this may lead to an infinite or to a never running loop
|
||||
|
||||
error: variables in the condition are not mutated in the loop body
|
||||
--> $DIR/infinite_loop.rs:88:11
|
||||
--> $DIR/infinite_loop.rs:87:11
|
||||
|
|
||||
LL | while i < 3 {
|
||||
| ^^^^^
|
||||
|
@ -48,7 +48,7 @@ LL | while i < 3 {
|
|||
= note: this may lead to an infinite or to a never running loop
|
||||
|
||||
error: variables in the condition are not mutated in the loop body
|
||||
--> $DIR/infinite_loop.rs:103:11
|
||||
--> $DIR/infinite_loop.rs:102:11
|
||||
|
|
||||
LL | while i < 3 {
|
||||
| ^^^^^
|
||||
|
@ -56,7 +56,7 @@ LL | while i < 3 {
|
|||
= note: this may lead to an infinite or to a never running loop
|
||||
|
||||
error: variables in the condition are not mutated in the loop body
|
||||
--> $DIR/infinite_loop.rs:108:11
|
||||
--> $DIR/infinite_loop.rs:107:11
|
||||
|
|
||||
LL | while i < 3 {
|
||||
| ^^^^^
|
||||
|
@ -64,7 +64,7 @@ LL | while i < 3 {
|
|||
= note: this may lead to an infinite or to a never running loop
|
||||
|
||||
error: variables in the condition are not mutated in the loop body
|
||||
--> $DIR/infinite_loop.rs:174:15
|
||||
--> $DIR/infinite_loop.rs:173:15
|
||||
|
|
||||
LL | while self.count < n {
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
@ -72,7 +72,7 @@ LL | while self.count < n {
|
|||
= note: this may lead to an infinite or to a never running loop
|
||||
|
||||
error: variables in the condition are not mutated in the loop body
|
||||
--> $DIR/infinite_loop.rs:182:11
|
||||
--> $DIR/infinite_loop.rs:181:11
|
||||
|
|
||||
LL | while y < 10 {
|
||||
| ^^^^^^
|
||||
|
@ -82,7 +82,7 @@ LL | while y < 10 {
|
|||
= help: rewrite it as `if cond { loop { } }`
|
||||
|
||||
error: variables in the condition are not mutated in the loop body
|
||||
--> $DIR/infinite_loop.rs:189:11
|
||||
--> $DIR/infinite_loop.rs:188:11
|
||||
|
|
||||
LL | while y < 10 {
|
||||
| ^^^^^^
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#![warn(clippy::inherent_to_string)]
|
||||
#![deny(clippy::inherent_to_string_shadow_display)]
|
||||
#![allow(clippy::many_single_char_names)]
|
||||
|
||||
use std::fmt;
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
error: implementation of inherent method `to_string(&self) -> String` for type `A`
|
||||
--> $DIR/inherent_to_string.rs:21:5
|
||||
--> $DIR/inherent_to_string.rs:20:5
|
||||
|
|
||||
LL | / fn to_string(&self) -> String {
|
||||
LL | | "A.to_string()".to_string()
|
||||
|
@ -10,7 +10,7 @@ LL | | }
|
|||
= help: implement trait `Display` for type `A` instead
|
||||
|
||||
error: type `C` implements inherent method `to_string(&self) -> String` which shadows the implementation of `Display`
|
||||
--> $DIR/inherent_to_string.rs:45:5
|
||||
--> $DIR/inherent_to_string.rs:44:5
|
||||
|
|
||||
LL | / fn to_string(&self) -> String {
|
||||
LL | | "C.to_string()".to_string()
|
||||
|
|
47
tests/ui/iter_not_returning_iterator.rs
Normal file
47
tests/ui/iter_not_returning_iterator.rs
Normal file
|
@ -0,0 +1,47 @@
|
|||
#![warn(clippy::iter_not_returning_iterator)]
|
||||
|
||||
struct Data {
|
||||
begin: u32,
|
||||
}
|
||||
|
||||
struct Counter {
|
||||
count: u32,
|
||||
}
|
||||
|
||||
impl Data {
|
||||
fn iter(&self) -> Counter {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn iter_mut(&self) -> Counter {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
struct Data2 {
|
||||
begin: u32,
|
||||
}
|
||||
|
||||
struct Counter2 {
|
||||
count: u32,
|
||||
}
|
||||
|
||||
impl Data2 {
|
||||
fn iter(&self) -> Counter2 {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn iter_mut(&self) -> Counter2 {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for Counter {
|
||||
type Item = u32;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
16
tests/ui/iter_not_returning_iterator.stderr
Normal file
16
tests/ui/iter_not_returning_iterator.stderr
Normal file
|
@ -0,0 +1,16 @@
|
|||
error: this method is named `iter` but its return type does not implement `Iterator`
|
||||
--> $DIR/iter_not_returning_iterator.rs:30:5
|
||||
|
|
||||
LL | fn iter(&self) -> Counter2 {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `-D clippy::iter-not-returning-iterator` implied by `-D warnings`
|
||||
|
||||
error: this method is named `iter_mut` but its return type does not implement `Iterator`
|
||||
--> $DIR/iter_not_returning_iterator.rs:34:5
|
||||
|
|
||||
LL | fn iter_mut(&self) -> Counter2 {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
#![allow(unused, clippy::many_single_char_names, clippy::diverging_sub_expression)]
|
||||
#![allow(unused, clippy::diverging_sub_expression)]
|
||||
#![warn(clippy::logic_bug)]
|
||||
|
||||
fn main() {
|
||||
|
|
|
@ -36,6 +36,12 @@ fn main() {
|
|||
|
||||
// Don't lint, slices don't have `split_once`
|
||||
let _ = [0, 1, 2].splitn(2, |&x| x == 1).nth(1).unwrap();
|
||||
|
||||
// `rsplitn` gives the results in the reverse order of `rsplit_once`
|
||||
let _ = "key=value".rsplit_once('=').unwrap().1;
|
||||
let _ = "key=value".rsplit_once('=').map_or("key=value", |x| x.0);
|
||||
let _ = "key=value".rsplit_once('=').map(|x| x.1);
|
||||
let (_, _) = "key=value".rsplit_once('=').map(|(x, y)| (y, x)).unwrap();
|
||||
}
|
||||
|
||||
fn _msrv_1_51() {
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue