mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-23 07:14:28 +00:00
Auto merge of #81560 - flip1995:clippyup, r=Manishearth
Update Clippy r? `@Manishearth` Biweekly Clippy update (2 days late)
This commit is contained in:
commit
b3897e3d13
@ -1,6 +1,7 @@
|
||||
[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 --"
|
||||
dev-lintcheck = "run --target-dir clippy_dev/target --package clippy_dev --bin clippy_dev --manifest-path clippy_dev/Cargo.toml --features lintcheck -- lintcheck"
|
||||
|
||||
[build]
|
||||
rustflags = ["-Zunstable-options"]
|
||||
|
@ -1878,6 +1878,7 @@ Released 2018-09-13
|
||||
[`boxed_local`]: https://rust-lang.github.io/rust-clippy/master/index.html#boxed_local
|
||||
[`builtin_type_shadow`]: https://rust-lang.github.io/rust-clippy/master/index.html#builtin_type_shadow
|
||||
[`cargo_common_metadata`]: https://rust-lang.github.io/rust-clippy/master/index.html#cargo_common_metadata
|
||||
[`case_sensitive_file_extension_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#case_sensitive_file_extension_comparisons
|
||||
[`cast_lossless`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_lossless
|
||||
[`cast_possible_truncation`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_possible_truncation
|
||||
[`cast_possible_wrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_possible_wrap
|
||||
@ -1937,6 +1938,8 @@ Released 2018-09-13
|
||||
[`erasing_op`]: https://rust-lang.github.io/rust-clippy/master/index.html#erasing_op
|
||||
[`eval_order_dependence`]: https://rust-lang.github.io/rust-clippy/master/index.html#eval_order_dependence
|
||||
[`excessive_precision`]: https://rust-lang.github.io/rust-clippy/master/index.html#excessive_precision
|
||||
[`exhaustive_enums`]: https://rust-lang.github.io/rust-clippy/master/index.html#exhaustive_enums
|
||||
[`exhaustive_structs`]: https://rust-lang.github.io/rust-clippy/master/index.html#exhaustive_structs
|
||||
[`exit`]: https://rust-lang.github.io/rust-clippy/master/index.html#exit
|
||||
[`expect_fun_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#expect_fun_call
|
||||
[`expect_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#expect_used
|
||||
@ -1996,6 +1999,7 @@ Released 2018-09-13
|
||||
[`inline_asm_x86_att_syntax`]: https://rust-lang.github.io/rust-clippy/master/index.html#inline_asm_x86_att_syntax
|
||||
[`inline_asm_x86_intel_syntax`]: https://rust-lang.github.io/rust-clippy/master/index.html#inline_asm_x86_intel_syntax
|
||||
[`inline_fn_without_body`]: https://rust-lang.github.io/rust-clippy/master/index.html#inline_fn_without_body
|
||||
[`inspect_for_each`]: https://rust-lang.github.io/rust-clippy/master/index.html#inspect_for_each
|
||||
[`int_plus_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#int_plus_one
|
||||
[`integer_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#integer_arithmetic
|
||||
[`integer_division`]: https://rust-lang.github.io/rust-clippy/master/index.html#integer_division
|
||||
@ -2033,6 +2037,8 @@ Released 2018-09-13
|
||||
[`macro_use_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#macro_use_imports
|
||||
[`main_recursion`]: https://rust-lang.github.io/rust-clippy/master/index.html#main_recursion
|
||||
[`manual_async_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_async_fn
|
||||
[`manual_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_filter_map
|
||||
[`manual_find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find_map
|
||||
[`manual_memcpy`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_memcpy
|
||||
[`manual_non_exhaustive`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_non_exhaustive
|
||||
[`manual_ok_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_ok_or
|
||||
@ -2161,6 +2167,7 @@ Released 2018-09-13
|
||||
[`redundant_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_pattern
|
||||
[`redundant_pattern_matching`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_pattern_matching
|
||||
[`redundant_pub_crate`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_pub_crate
|
||||
[`redundant_slicing`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_slicing
|
||||
[`redundant_static_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_static_lifetimes
|
||||
[`ref_in_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_in_deref
|
||||
[`ref_option_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_option_ref
|
||||
@ -2271,6 +2278,7 @@ Released 2018-09-13
|
||||
[`unusual_byte_groupings`]: https://rust-lang.github.io/rust-clippy/master/index.html#unusual_byte_groupings
|
||||
[`unwrap_in_result`]: https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_in_result
|
||||
[`unwrap_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_used
|
||||
[`upper_case_acronyms`]: https://rust-lang.github.io/rust-clippy/master/index.html#upper_case_acronyms
|
||||
[`use_debug`]: https://rust-lang.github.io/rust-clippy/master/index.html#use_debug
|
||||
[`use_self`]: https://rust-lang.github.io/rust-clippy/master/index.html#use_self
|
||||
[`used_underscore_binding`]: https://rust-lang.github.io/rust-clippy/master/index.html#used_underscore_binding
|
||||
|
@ -310,10 +310,19 @@ currently. Between writing new lints, fixing issues, reviewing pull requests and
|
||||
responding to issues there may not always be enough time to stay on top of it
|
||||
all.
|
||||
|
||||
Our highest priority is fixing [crashes][l-crash] and [bugs][l-bug]. We don't
|
||||
Our highest priority is fixing [crashes][l-crash] and [bugs][l-bug], for example
|
||||
an ICE in a popular crate that many other crates depend on. We don't
|
||||
want Clippy to crash on your code and we want it to be as reliable as the
|
||||
suggestions from Rust compiler errors.
|
||||
|
||||
We have prioritization labels and a sync-blocker label, which are described below.
|
||||
- [P-low][p-low]: Requires attention (fix/response/evaluation) by a team member but isn't urgent.
|
||||
- [P-medium][p-medium]: Should be addressed by a team member until the next sync.
|
||||
- [P-high][p-high]: Should be immediately addressed and will require an out-of-cycle sync or a backport.
|
||||
- [L-sync-blocker][l-sync-blocker]: An issue that "blocks" a sync.
|
||||
Or rather: before the sync this should be addressed,
|
||||
e.g. by removing a lint again, so it doesn't hit beta/stable.
|
||||
|
||||
## Bors and Homu
|
||||
|
||||
We use a bot powered by [Homu][homu] to help automate testing and landing of pull
|
||||
@ -327,6 +336,10 @@ commands [here][homu_instructions].
|
||||
[triage]: https://forge.rust-lang.org/release/triage-procedure.html
|
||||
[l-crash]: https://github.com/rust-lang/rust-clippy/labels/L-crash
|
||||
[l-bug]: https://github.com/rust-lang/rust-clippy/labels/L-bug
|
||||
[p-low]: https://github.com/rust-lang/rust-clippy/labels/P-low
|
||||
[p-medium]: https://github.com/rust-lang/rust-clippy/labels/P-medium
|
||||
[p-high]: https://github.com/rust-lang/rust-clippy/labels/P-high
|
||||
[l-sync-blocker]: https://github.com/rust-lang/rust-clippy/labels/L-sync-blocker
|
||||
[homu]: https://github.com/rust-lang/homu
|
||||
[homu_instructions]: https://bors.rust-lang.org/
|
||||
[homu_queue]: https://bors.rust-lang.org/queue/clippy
|
||||
|
@ -4,14 +4,22 @@ version = "0.0.1"
|
||||
authors = ["Philipp Hansch <dev@phansch.net>"]
|
||||
edition = "2018"
|
||||
|
||||
|
||||
[dependencies]
|
||||
bytecount = "0.6"
|
||||
clap = "2.33"
|
||||
flate2 = { version = "1.0.19", optional = true }
|
||||
itertools = "0.9"
|
||||
opener = "0.4"
|
||||
regex = "1"
|
||||
serde = { version = "1.0", features = ["derive"], optional = true }
|
||||
serde_json = { version = "1.0", optional = true }
|
||||
shell-escape = "0.1"
|
||||
tar = { version = "0.4.30", optional = true }
|
||||
toml = { version = "0.5", optional = true }
|
||||
ureq = { version = "2.0.0-rc3", optional = true }
|
||||
walkdir = "2"
|
||||
|
||||
[features]
|
||||
lintcheck = ["flate2", "serde_json", "tar", "toml", "ureq", "serde"]
|
||||
deny-warnings = []
|
||||
|
20
src/tools/clippy/clippy_dev/lintcheck_crates.toml
Normal file
20
src/tools/clippy/clippy_dev/lintcheck_crates.toml
Normal file
@ -0,0 +1,20 @@
|
||||
[crates]
|
||||
# some of these are from cargotest
|
||||
cargo = ['0.49.0']
|
||||
iron = ['0.6.1']
|
||||
ripgrep = ['12.1.1']
|
||||
xsv = ['0.13.0']
|
||||
#tokei = ['12.0.4']
|
||||
rayon = ['1.5.0']
|
||||
serde = ['1.0.118']
|
||||
# top 10 crates.io dls
|
||||
bitflags = ['1.2.1']
|
||||
libc = ['0.2.81']
|
||||
log = ['0.4.11']
|
||||
proc-macro2 = ['1.0.24']
|
||||
quote = ['1.0.7']
|
||||
rand = ['0.7.3']
|
||||
rand_core = ['0.6.0']
|
||||
regex = ['1.3.2']
|
||||
syn = ['1.0.54']
|
||||
unicode-xid = ['0.2.1']
|
@ -12,6 +12,7 @@ use walkdir::WalkDir;
|
||||
|
||||
pub mod bless;
|
||||
pub mod fmt;
|
||||
pub mod lintcheck;
|
||||
pub mod new_lint;
|
||||
pub mod ra_setup;
|
||||
pub mod serve;
|
||||
|
286
src/tools/clippy/clippy_dev/src/lintcheck.rs
Normal file
286
src/tools/clippy/clippy_dev/src/lintcheck.rs
Normal file
@ -0,0 +1,286 @@
|
||||
// Run clippy on a fixed set of crates and collect the warnings.
|
||||
// This helps observing the impact clippy changs have on a set of real-world code.
|
||||
//
|
||||
// When a new lint is introduced, we can search the results for new warnings and check for false
|
||||
// positives.
|
||||
|
||||
#![cfg(feature = "lintcheck")]
|
||||
#![allow(clippy::filter_map)]
|
||||
|
||||
use crate::clippy_project_root;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::process::Command;
|
||||
use std::{fmt, fs::write, path::PathBuf};
|
||||
|
||||
use clap::ArgMatches;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
|
||||
// use this to store the crates when interacting with the crates.toml file
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
struct CrateList {
|
||||
crates: HashMap<String, Vec<String>>,
|
||||
}
|
||||
|
||||
// crate data we stored in the toml, can have multiple versions per crate
|
||||
// A single TomlCrate is laster mapped to several CrateSources in that case
|
||||
struct TomlCrate {
|
||||
name: String,
|
||||
versions: Vec<String>,
|
||||
}
|
||||
|
||||
// represents an archive we download from crates.io
|
||||
#[derive(Debug, Serialize, Deserialize, Eq, Hash, PartialEq)]
|
||||
struct CrateSource {
|
||||
name: String,
|
||||
version: String,
|
||||
}
|
||||
|
||||
// represents the extracted sourcecode of a crate
|
||||
#[derive(Debug)]
|
||||
struct Crate {
|
||||
version: String,
|
||||
name: String,
|
||||
// path to the extracted sources that clippy can check
|
||||
path: PathBuf,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct ClippyWarning {
|
||||
crate_name: String,
|
||||
crate_version: String,
|
||||
file: String,
|
||||
line: String,
|
||||
column: String,
|
||||
linttype: String,
|
||||
message: String,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for ClippyWarning {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
writeln!(
|
||||
f,
|
||||
r#"{}-{}/{}:{}:{} {} "{}""#,
|
||||
&self.crate_name, &self.crate_version, &self.file, &self.line, &self.column, &self.linttype, &self.message
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl CrateSource {
|
||||
fn download_and_extract(&self) -> Crate {
|
||||
let extract_dir = PathBuf::from("target/lintcheck/crates");
|
||||
let krate_download_dir = PathBuf::from("target/lintcheck/downloads");
|
||||
|
||||
// url to download the crate from crates.io
|
||||
let url = format!(
|
||||
"https://crates.io/api/v1/crates/{}/{}/download",
|
||||
self.name, self.version
|
||||
);
|
||||
println!("Downloading and extracting {} {} from {}", self.name, self.version, url);
|
||||
let _ = std::fs::create_dir("target/lintcheck/");
|
||||
let _ = std::fs::create_dir(&krate_download_dir);
|
||||
let _ = std::fs::create_dir(&extract_dir);
|
||||
|
||||
let krate_file_path = krate_download_dir.join(format!("{}-{}.crate.tar.gz", &self.name, &self.version));
|
||||
// don't download/extract if we already have done so
|
||||
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();
|
||||
// copy the crate into the file
|
||||
std::io::copy(&mut krate_req, &mut krate_dest).unwrap();
|
||||
|
||||
// unzip the tarball
|
||||
let ungz_tar = flate2::read::GzDecoder::new(std::fs::File::open(&krate_file_path).unwrap());
|
||||
// extract the tar archive
|
||||
let mut archive = tar::Archive::new(ungz_tar);
|
||||
archive.unpack(&extract_dir).expect("Failed to extract!");
|
||||
}
|
||||
// crate is extracted, return a new Krate object which contains the path to the extracted
|
||||
// sources that clippy can check
|
||||
Crate {
|
||||
version: self.version.clone(),
|
||||
name: self.name.clone(),
|
||||
path: extract_dir.join(format!("{}-{}/", self.name, self.version)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Crate {
|
||||
fn run_clippy_lints(&self, cargo_clippy_path: &PathBuf) -> Vec<ClippyWarning> {
|
||||
println!("Linting {} {}...", &self.name, &self.version);
|
||||
let cargo_clippy_path = std::fs::canonicalize(cargo_clippy_path).unwrap();
|
||||
|
||||
let shared_target_dir = clippy_project_root().join("target/lintcheck/shared_target_dir/");
|
||||
|
||||
let all_output = std::process::Command::new(cargo_clippy_path)
|
||||
.env("CARGO_TARGET_DIR", shared_target_dir)
|
||||
// lint warnings will look like this:
|
||||
// src/cargo/ops/cargo_compile.rs:127:35: warning: usage of `FromIterator::from_iter`
|
||||
.args(&[
|
||||
"--",
|
||||
"--message-format=json",
|
||||
"--",
|
||||
"--cap-lints=warn",
|
||||
"-Wclippy::pedantic",
|
||||
"-Wclippy::cargo",
|
||||
])
|
||||
.current_dir(&self.path)
|
||||
.output()
|
||||
.unwrap();
|
||||
let stdout = String::from_utf8_lossy(&all_output.stdout);
|
||||
let output_lines = stdout.lines();
|
||||
//dbg!(&output_lines);
|
||||
let warnings: Vec<ClippyWarning> = output_lines
|
||||
.into_iter()
|
||||
// get all clippy warnings
|
||||
.filter(|line| line.contains("clippy::"))
|
||||
.map(|json_msg| parse_json_message(json_msg, &self))
|
||||
.collect();
|
||||
warnings
|
||||
}
|
||||
}
|
||||
|
||||
fn build_clippy() {
|
||||
Command::new("cargo")
|
||||
.arg("build")
|
||||
.output()
|
||||
.expect("Failed to build clippy!");
|
||||
}
|
||||
|
||||
// get a list of CrateSources we want to check from a "lintcheck_crates.toml" file.
|
||||
fn read_crates() -> Vec<CrateSource> {
|
||||
let toml_path = PathBuf::from("clippy_dev/lintcheck_crates.toml");
|
||||
let toml_content: String =
|
||||
std::fs::read_to_string(&toml_path).unwrap_or_else(|_| panic!("Failed to read {}", toml_path.display()));
|
||||
let crate_list: CrateList =
|
||||
toml::from_str(&toml_content).unwrap_or_else(|e| panic!("Failed to parse {}: \n{}", toml_path.display(), e));
|
||||
// parse the hashmap of the toml file into a list of crates
|
||||
let tomlcrates: Vec<TomlCrate> = crate_list
|
||||
.crates
|
||||
.into_iter()
|
||||
.map(|(name, versions)| TomlCrate { name, versions })
|
||||
.collect();
|
||||
|
||||
// flatten TomlCrates into CrateSources (one TomlCrates may represent several versions of a crate =>
|
||||
// multiple Cratesources)
|
||||
let mut crate_sources = Vec::new();
|
||||
tomlcrates.into_iter().for_each(|tk| {
|
||||
tk.versions.iter().for_each(|ver| {
|
||||
crate_sources.push(CrateSource {
|
||||
name: tk.name.clone(),
|
||||
version: ver.to_string(),
|
||||
});
|
||||
})
|
||||
});
|
||||
crate_sources
|
||||
}
|
||||
|
||||
// extract interesting data from a json lint message
|
||||
fn parse_json_message(json_message: &str, krate: &Crate) -> ClippyWarning {
|
||||
let jmsg: Value = serde_json::from_str(&json_message).unwrap_or_else(|e| panic!("Failed to parse json:\n{:?}", e));
|
||||
|
||||
ClippyWarning {
|
||||
crate_name: krate.name.to_string(),
|
||||
crate_version: krate.version.to_string(),
|
||||
file: jmsg["message"]["spans"][0]["file_name"]
|
||||
.to_string()
|
||||
.trim_matches('"')
|
||||
.into(),
|
||||
line: jmsg["message"]["spans"][0]["line_start"]
|
||||
.to_string()
|
||||
.trim_matches('"')
|
||||
.into(),
|
||||
column: jmsg["message"]["spans"][0]["text"][0]["highlight_start"]
|
||||
.to_string()
|
||||
.trim_matches('"')
|
||||
.into(),
|
||||
linttype: jmsg["message"]["code"]["code"].to_string().trim_matches('"').into(),
|
||||
message: jmsg["message"]["message"].to_string().trim_matches('"').into(),
|
||||
}
|
||||
}
|
||||
|
||||
// the main fn
|
||||
pub fn run(clap_config: &ArgMatches) {
|
||||
let cargo_clippy_path: PathBuf = PathBuf::from("target/debug/cargo-clippy");
|
||||
|
||||
println!("Compiling clippy...");
|
||||
build_clippy();
|
||||
println!("Done compiling");
|
||||
|
||||
// assert that clippy is found
|
||||
assert!(
|
||||
cargo_clippy_path.is_file(),
|
||||
"target/debug/cargo-clippy binary not found! {}",
|
||||
cargo_clippy_path.display()
|
||||
);
|
||||
|
||||
let clippy_ver = std::process::Command::new("target/debug/cargo-clippy")
|
||||
.arg("--version")
|
||||
.output()
|
||||
.map(|o| String::from_utf8_lossy(&o.stdout).into_owned())
|
||||
.expect("could not get clippy version!");
|
||||
|
||||
// download and extract the crates, then run clippy on them and collect clippys warnings
|
||||
// flatten into one big list of warnings
|
||||
|
||||
let crates = read_crates();
|
||||
|
||||
let clippy_warnings: Vec<ClippyWarning> = if let Some(only_one_crate) = clap_config.value_of("only") {
|
||||
// if we don't have the specified crated in the .toml, throw an error
|
||||
if !crates.iter().any(|krate| krate.name == only_one_crate) {
|
||||
eprintln!(
|
||||
"ERROR: could not find crate '{}' in clippy_dev/lintcheck_crates.toml",
|
||||
only_one_crate
|
||||
);
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
// only check a single crate that was passed via cmdline
|
||||
crates
|
||||
.into_iter()
|
||||
.map(|krate| krate.download_and_extract())
|
||||
.filter(|krate| krate.name == only_one_crate)
|
||||
.map(|krate| krate.run_clippy_lints(&cargo_clippy_path))
|
||||
.flatten()
|
||||
.collect()
|
||||
} else {
|
||||
// check all crates (default)
|
||||
crates
|
||||
.into_iter()
|
||||
.map(|krate| krate.download_and_extract())
|
||||
.map(|krate| krate.run_clippy_lints(&cargo_clippy_path))
|
||||
.flatten()
|
||||
.collect()
|
||||
};
|
||||
|
||||
// generate some stats:
|
||||
|
||||
// count lint type occurrences
|
||||
let mut counter: HashMap<&String, usize> = HashMap::new();
|
||||
clippy_warnings
|
||||
.iter()
|
||||
.for_each(|wrn| *counter.entry(&wrn.linttype).or_insert(0) += 1);
|
||||
|
||||
// collect into a tupled list for sorting
|
||||
let mut stats: Vec<(&&String, &usize)> = counter.iter().map(|(lint, count)| (lint, count)).collect();
|
||||
// sort by "000{count} {clippy::lintname}"
|
||||
// to not have a lint with 200 and 2 warnings take the same spot
|
||||
stats.sort_by_key(|(lint, count)| format!("{:0>4}, {}", count, lint));
|
||||
|
||||
let stats_formatted: String = stats
|
||||
.iter()
|
||||
.map(|(lint, count)| format!("{} {}\n", lint, count))
|
||||
.collect::<String>();
|
||||
|
||||
let mut all_msgs: Vec<String> = clippy_warnings.iter().map(|warning| warning.to_string()).collect();
|
||||
all_msgs.sort();
|
||||
all_msgs.push("\n\n\n\nStats\n\n".into());
|
||||
all_msgs.push(stats_formatted);
|
||||
|
||||
// save the text into lintcheck-logs/logs.txt
|
||||
let mut text = clippy_ver; // clippy version number on top
|
||||
text.push_str(&format!("\n{}", all_msgs.join("")));
|
||||
write("lintcheck-logs/logs.txt", text).unwrap();
|
||||
}
|
@ -3,6 +3,9 @@
|
||||
use clap::{App, Arg, ArgMatches, SubCommand};
|
||||
use clippy_dev::{bless, fmt, new_lint, ra_setup, serve, stderr_length_check, update_lints};
|
||||
|
||||
#[cfg(feature = "lintcheck")]
|
||||
use clippy_dev::lintcheck;
|
||||
|
||||
fn main() {
|
||||
let matches = get_clap_config();
|
||||
|
||||
@ -10,6 +13,10 @@ fn main() {
|
||||
("bless", Some(matches)) => {
|
||||
bless::bless(matches.is_present("ignore-timestamp"));
|
||||
},
|
||||
#[cfg(feature = "lintcheck")]
|
||||
("lintcheck", Some(matches)) => {
|
||||
lintcheck::run(&matches);
|
||||
},
|
||||
("fmt", Some(matches)) => {
|
||||
fmt::run(matches.is_present("check"), matches.is_present("verbose"));
|
||||
},
|
||||
@ -46,7 +53,18 @@ fn main() {
|
||||
}
|
||||
|
||||
fn get_clap_config<'a>() -> ArgMatches<'a> {
|
||||
App::new("Clippy developer tooling")
|
||||
#[cfg(feature = "lintcheck")]
|
||||
let lintcheck_sbcmd = SubCommand::with_name("lintcheck")
|
||||
.about("run clippy on a set of crates and check output")
|
||||
.arg(
|
||||
Arg::with_name("only")
|
||||
.takes_value(true)
|
||||
.value_name("CRATE")
|
||||
.long("only")
|
||||
.help("only process a single crate of the list"),
|
||||
);
|
||||
|
||||
let app = App::new("Clippy developer tooling")
|
||||
.subcommand(
|
||||
SubCommand::with_name("bless")
|
||||
.about("bless the test output changes")
|
||||
@ -163,6 +181,10 @@ fn get_clap_config<'a>() -> ArgMatches<'a> {
|
||||
.validator_os(serve::validate_port),
|
||||
)
|
||||
.arg(Arg::with_name("lint").help("Which lint's page to load initially (optional)")),
|
||||
)
|
||||
.get_matches()
|
||||
);
|
||||
|
||||
#[cfg(feature = "lintcheck")]
|
||||
let app = app.subcommand(lintcheck_sbcmd);
|
||||
|
||||
app.get_matches()
|
||||
}
|
||||
|
@ -1,5 +1,3 @@
|
||||
#![allow(clippy::filter_map)]
|
||||
|
||||
use std::fs;
|
||||
use std::fs::File;
|
||||
use std::io::prelude::*;
|
||||
|
@ -8,6 +8,14 @@ use crate::utils::span_lint_and_help;
|
||||
declare_clippy_lint! {
|
||||
/// **What it does:** Checks for usage of `as` conversions.
|
||||
///
|
||||
/// Note that this lint is specialized in linting *every single* use of `as`
|
||||
/// regardless of whether good alternatives exist or not.
|
||||
/// If you want more precise lints for `as`, please consider using these separate lints:
|
||||
/// `unnecessary_cast`, `cast_lossless/possible_truncation/possible_wrap/precision_loss/sign_loss`,
|
||||
/// `fn_to_numeric_cast(_with_truncation)`, `char_lit_as_u8`, `ref_to_mut` and `ptr_as_ptr`.
|
||||
/// There is a good explanation the reason why this lint should work in this way and how it is useful
|
||||
/// [in this issue](https://github.com/rust-lang/rust-clippy/issues/5122).
|
||||
///
|
||||
/// **Why is this bad?** `as` conversions will perform many kinds of
|
||||
/// conversions, including silently lossy conversions and dangerous coercions.
|
||||
/// There are cases when it makes sense to use `as`, so the lint is
|
||||
|
@ -18,7 +18,7 @@ declare_clippy_lint! {
|
||||
/// other solution is to ensure the mutex is unlocked before calling await,
|
||||
/// either by introducing a scope or an explicit call to Drop::drop.
|
||||
///
|
||||
/// **Known problems:** None.
|
||||
/// **Known problems:** Will report false positive for explicitly dropped guards ([#6446](https://github.com/rust-lang/rust-clippy/issues/6446)).
|
||||
///
|
||||
/// **Example:**
|
||||
///
|
||||
@ -57,7 +57,7 @@ declare_clippy_lint! {
|
||||
/// at runtime. Holding onto a `RefCell` ref across an `await` suspension point
|
||||
/// risks panics from a mutable ref shared while other refs are outstanding.
|
||||
///
|
||||
/// **Known problems:** None.
|
||||
/// **Known problems:** Will report false positive for explicitly dropped refs ([#6353](https://github.com/rust-lang/rust-clippy/issues/6353)).
|
||||
///
|
||||
/// **Example:**
|
||||
///
|
||||
|
@ -0,0 +1,86 @@
|
||||
use crate::utils::paths::STRING;
|
||||
use crate::utils::{match_def_path, span_lint_and_help};
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::ast::LitKind;
|
||||
use rustc_hir::{Expr, ExprKind, PathSegment};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty;
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::{source_map::Spanned, Span};
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// **What it does:**
|
||||
/// Checks for calls to `ends_with` with possible file extensions
|
||||
/// and suggests to use a case-insensitive approach instead.
|
||||
///
|
||||
/// **Why is this bad?**
|
||||
/// `ends_with` is case-sensitive and may not detect files with a valid extension.
|
||||
///
|
||||
/// **Known problems:** None.
|
||||
///
|
||||
/// **Example:**
|
||||
///
|
||||
/// ```rust
|
||||
/// fn is_rust_file(filename: &str) -> bool {
|
||||
/// filename.ends_with(".rs")
|
||||
/// }
|
||||
/// ```
|
||||
/// Use instead:
|
||||
/// ```rust
|
||||
/// fn is_rust_file(filename: &str) -> bool {
|
||||
/// filename.rsplit('.').next().map(|ext| ext.eq_ignore_ascii_case("rs")) == Some(true)
|
||||
/// }
|
||||
/// ```
|
||||
pub CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS,
|
||||
pedantic,
|
||||
"Checks for calls to ends_with with case-sensitive file extensions"
|
||||
}
|
||||
|
||||
declare_lint_pass!(CaseSensitiveFileExtensionComparisons => [CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS]);
|
||||
|
||||
fn check_case_sensitive_file_extension_comparison(ctx: &LateContext<'_>, expr: &Expr<'_>) -> Option<Span> {
|
||||
if_chain! {
|
||||
if let ExprKind::MethodCall(PathSegment { ident, .. }, _, [obj, extension, ..], span) = expr.kind;
|
||||
if ident.as_str() == "ends_with";
|
||||
if let ExprKind::Lit(Spanned { node: LitKind::Str(ext_literal, ..), ..}) = extension.kind;
|
||||
if (2..=6).contains(&ext_literal.as_str().len());
|
||||
if ext_literal.as_str().starts_with('.');
|
||||
if ext_literal.as_str().chars().skip(1).all(|c| c.is_uppercase() || c.is_digit(10))
|
||||
|| ext_literal.as_str().chars().skip(1).all(|c| c.is_lowercase() || c.is_digit(10));
|
||||
then {
|
||||
let mut ty = ctx.typeck_results().expr_ty(obj);
|
||||
ty = match ty.kind() {
|
||||
ty::Ref(_, ty, ..) => ty,
|
||||
_ => ty
|
||||
};
|
||||
|
||||
match ty.kind() {
|
||||
ty::Str => {
|
||||
return Some(span);
|
||||
},
|
||||
ty::Adt(&ty::AdtDef { did, .. }, _) => {
|
||||
if match_def_path(ctx, did, &STRING) {
|
||||
return Some(span);
|
||||
}
|
||||
},
|
||||
_ => { return None; }
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
impl LateLintPass<'tcx> for CaseSensitiveFileExtensionComparisons {
|
||||
fn check_expr(&mut self, ctx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
|
||||
if let Some(span) = check_case_sensitive_file_extension_comparison(ctx, expr) {
|
||||
span_lint_and_help(
|
||||
ctx,
|
||||
CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS,
|
||||
span,
|
||||
"case-sensitive file extension comparison",
|
||||
None,
|
||||
"consider using a case-insensitive comparison instead",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
@ -57,9 +57,9 @@ impl CognitiveComplexity {
|
||||
|
||||
let expr = &body.value;
|
||||
|
||||
let mut helper = CCHelper { cc: 1, returns: 0 };
|
||||
let mut helper = CcHelper { cc: 1, returns: 0 };
|
||||
helper.visit_expr(expr);
|
||||
let CCHelper { cc, returns } = helper;
|
||||
let CcHelper { cc, returns } = helper;
|
||||
let ret_ty = cx.typeck_results().node_type(expr.hir_id);
|
||||
let ret_adjust = if is_type_diagnostic_item(cx, ret_ty, sym::result_type) {
|
||||
returns
|
||||
@ -136,12 +136,12 @@ impl<'tcx> LateLintPass<'tcx> for CognitiveComplexity {
|
||||
}
|
||||
}
|
||||
|
||||
struct CCHelper {
|
||||
struct CcHelper {
|
||||
cc: u64,
|
||||
returns: u64,
|
||||
}
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for CCHelper {
|
||||
impl<'tcx> Visitor<'tcx> for CcHelper {
|
||||
type Map = Map<'tcx>;
|
||||
|
||||
fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
|
||||
|
@ -2,7 +2,7 @@ use crate::utils::visitors::LocalUsedVisitor;
|
||||
use crate::utils::{span_lint_and_then, SpanlessEq};
|
||||
use if_chain::if_chain;
|
||||
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
|
||||
use rustc_hir::{Arm, Expr, ExprKind, Guard, HirId, Pat, PatKind, QPath, StmtKind};
|
||||
use rustc_hir::{Arm, Expr, ExprKind, Guard, HirId, Pat, PatKind, QPath, StmtKind, UnOp};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty::{DefIdTree, TyCtxt};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
@ -72,8 +72,7 @@ fn check_arm(arm: &Arm<'_>, wild_outer_arm: &Arm<'_>, cx: &LateContext<'_>) {
|
||||
if arms_inner.iter().all(|arm| arm.guard.is_none());
|
||||
// match expression must be a local binding
|
||||
// match <local> { .. }
|
||||
if let ExprKind::Path(QPath::Resolved(None, path)) = expr_in.kind;
|
||||
if let Res::Local(binding_id) = path.res;
|
||||
if let Some(binding_id) = addr_adjusted_binding(expr_in, cx);
|
||||
// one of the branches must be "wild-like"
|
||||
if let Some(wild_inner_arm_idx) = arms_inner.iter().rposition(|arm_inner| arm_is_wild_like(arm_inner, cx.tcx));
|
||||
let (wild_inner_arm, non_wild_inner_arm) =
|
||||
@ -85,7 +84,12 @@ fn check_arm(arm: &Arm<'_>, wild_outer_arm: &Arm<'_>, cx: &LateContext<'_>) {
|
||||
// the "wild-like" branches must be equal
|
||||
if SpanlessEq::new(cx).eq_expr(wild_inner_arm.body, wild_outer_arm.body);
|
||||
// the binding must not be used in the if guard
|
||||
if !matches!(arm.guard, Some(Guard::If(guard)) if LocalUsedVisitor::new(binding_id).check_expr(guard));
|
||||
if match arm.guard {
|
||||
None => true,
|
||||
Some(Guard::If(expr) | Guard::IfLet(_, expr)) => {
|
||||
!LocalUsedVisitor::new(binding_id).check_expr(expr)
|
||||
}
|
||||
};
|
||||
// ...or anywhere in the inner match
|
||||
if !arms_inner.iter().any(|arm| LocalUsedVisitor::new(binding_id).check_arm(arm));
|
||||
then {
|
||||
@ -170,3 +174,20 @@ fn is_none_ctor(res: Res, tcx: TyCtxt<'_>) -> bool {
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// Retrieves a binding ID with optional `&` and/or `*` operators removed. (e.g. `&**foo`)
|
||||
/// Returns `None` if a non-reference type is de-referenced.
|
||||
/// For example, if `Vec` is de-referenced to a slice, `None` is returned.
|
||||
fn addr_adjusted_binding(mut expr: &Expr<'_>, cx: &LateContext<'_>) -> Option<HirId> {
|
||||
loop {
|
||||
match expr.kind {
|
||||
ExprKind::AddrOf(_, _, e) => expr = e,
|
||||
ExprKind::Path(QPath::Resolved(None, path)) => match path.res {
|
||||
Res::Local(binding_id) => break Some(binding_id),
|
||||
_ => break None,
|
||||
},
|
||||
ExprKind::Unary(UnOp::UnDeref, e) if cx.typeck_results().expr_ty(e).is_ref() => expr = e,
|
||||
_ => break None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -179,3 +179,12 @@ declare_deprecated_lint! {
|
||||
pub UNKNOWN_CLIPPY_LINTS,
|
||||
"this lint has been integrated into the `unknown_lints` rustc lint"
|
||||
}
|
||||
|
||||
declare_deprecated_lint! {
|
||||
/// **What it does:** Nothing. This lint has been deprecated.
|
||||
///
|
||||
/// **Deprecation reason:** This lint has been replaced by `manual_find_map`, a
|
||||
/// more specific lint.
|
||||
pub FIND_MAP,
|
||||
"this lint has been replaced by `manual_find_map`, a more specific lint"
|
||||
}
|
||||
|
@ -5,8 +5,8 @@ use crate::consts::{miri_to_const, Constant};
|
||||
use crate::utils::span_lint;
|
||||
use rustc_hir::{Item, ItemKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty::{self, IntTy, UintTy};
|
||||
use rustc_middle::ty::util::IntTypeExt;
|
||||
use rustc_middle::ty::{self, IntTy, UintTy};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use std::convert::TryFrom;
|
||||
|
||||
|
102
src/tools/clippy/clippy_lints/src/exhaustive_items.rs
Normal file
102
src/tools/clippy/clippy_lints/src/exhaustive_items.rs
Normal file
@ -0,0 +1,102 @@
|
||||
use crate::utils::{indent_of, span_lint_and_then};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Item, ItemKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::sym;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// **What it does:** Warns on any exported `enum`s that are not tagged `#[non_exhaustive]`
|
||||
///
|
||||
/// **Why is this bad?** Exhaustive enums are typically fine, but a project which does
|
||||
/// not wish to make a stability commitment around exported enums may wish to
|
||||
/// disable them by default.
|
||||
///
|
||||
/// **Known problems:** None.
|
||||
///
|
||||
/// **Example:**
|
||||
///
|
||||
/// ```rust
|
||||
/// enum Foo {
|
||||
/// Bar,
|
||||
/// Baz
|
||||
/// }
|
||||
/// ```
|
||||
/// Use instead:
|
||||
/// ```rust
|
||||
/// #[non_exhaustive]
|
||||
/// enum Foo {
|
||||
/// Bar,
|
||||
/// Baz
|
||||
/// }
|
||||
/// ```
|
||||
pub EXHAUSTIVE_ENUMS,
|
||||
restriction,
|
||||
"detects exported enums that have not been marked #[non_exhaustive]"
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// **What it does:** Warns on any exported `structs`s that are not tagged `#[non_exhaustive]`
|
||||
///
|
||||
/// **Why is this bad?** Exhaustive structs are typically fine, but a project which does
|
||||
/// not wish to make a stability commitment around exported structs may wish to
|
||||
/// disable them by default.
|
||||
///
|
||||
/// **Known problems:** None.
|
||||
///
|
||||
/// **Example:**
|
||||
///
|
||||
/// ```rust
|
||||
/// struct Foo {
|
||||
/// bar: u8,
|
||||
/// baz: String,
|
||||
/// }
|
||||
/// ```
|
||||
/// Use instead:
|
||||
/// ```rust
|
||||
/// #[non_exhaustive]
|
||||
/// struct Foo {
|
||||
/// bar: u8,
|
||||
/// baz: String,
|
||||
/// }
|
||||
/// ```
|
||||
pub EXHAUSTIVE_STRUCTS,
|
||||
restriction,
|
||||
"detects exported structs that have not been marked #[non_exhaustive]"
|
||||
}
|
||||
|
||||
declare_lint_pass!(ExhaustiveItems => [EXHAUSTIVE_ENUMS, EXHAUSTIVE_STRUCTS]);
|
||||
|
||||
impl LateLintPass<'_> for ExhaustiveItems {
|
||||
fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
|
||||
if_chain! {
|
||||
if let ItemKind::Enum(..) | ItemKind::Struct(..) = item.kind;
|
||||
if cx.access_levels.is_exported(item.hir_id);
|
||||
if !item.attrs.iter().any(|a| a.has_name(sym::non_exhaustive));
|
||||
then {
|
||||
let (lint, msg) = if let ItemKind::Enum(..) = item.kind {
|
||||
(EXHAUSTIVE_ENUMS, "exported enums should not be exhaustive")
|
||||
} else {
|
||||
(EXHAUSTIVE_STRUCTS, "exported structs should not be exhaustive")
|
||||
};
|
||||
let suggestion_span = item.span.shrink_to_lo();
|
||||
let indent = " ".repeat(indent_of(cx, item.span).unwrap_or(0));
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
lint,
|
||||
item.span,
|
||||
msg,
|
||||
|diag| {
|
||||
let sugg = format!("#[non_exhaustive]\n{}", indent);
|
||||
diag.span_suggestion(suggestion_span,
|
||||
"try adding #[non_exhaustive]",
|
||||
sugg,
|
||||
Applicability::MaybeIncorrect);
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -92,13 +92,8 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend {
|
||||
|db| {
|
||||
cx.tcx.infer_ctxt().enter(|infcx| {
|
||||
for FulfillmentError { obligation, .. } in send_errors {
|
||||
infcx.maybe_note_obligation_cause_for_async_await(
|
||||
db,
|
||||
&obligation,
|
||||
);
|
||||
if let Trait(trait_pred, _) =
|
||||
obligation.predicate.kind().skip_binder()
|
||||
{
|
||||
infcx.maybe_note_obligation_cause_for_async_await(db, &obligation);
|
||||
if let Trait(trait_pred, _) = obligation.predicate.kind().skip_binder() {
|
||||
db.note(&format!(
|
||||
"`{}` doesn't implement `{}`",
|
||||
trait_pred.self_ty(),
|
||||
|
@ -46,8 +46,8 @@ declare_lint_pass!(IntPlusOne => [INT_PLUS_ONE]);
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
enum Side {
|
||||
LHS,
|
||||
RHS,
|
||||
Lhs,
|
||||
Rhs,
|
||||
}
|
||||
|
||||
impl IntPlusOne {
|
||||
@ -66,11 +66,11 @@ impl IntPlusOne {
|
||||
match (lhskind.node, &lhslhs.kind, &lhsrhs.kind) {
|
||||
// `-1 + x`
|
||||
(BinOpKind::Add, &ExprKind::Lit(ref lit), _) if Self::check_lit(lit, -1) => {
|
||||
Self::generate_recommendation(cx, binop, lhsrhs, rhs, Side::LHS)
|
||||
Self::generate_recommendation(cx, binop, lhsrhs, rhs, Side::Lhs)
|
||||
},
|
||||
// `x - 1`
|
||||
(BinOpKind::Sub, _, &ExprKind::Lit(ref lit)) if Self::check_lit(lit, 1) => {
|
||||
Self::generate_recommendation(cx, binop, lhslhs, rhs, Side::LHS)
|
||||
Self::generate_recommendation(cx, binop, lhslhs, rhs, Side::Lhs)
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
@ -82,10 +82,10 @@ impl IntPlusOne {
|
||||
match (&rhslhs.kind, &rhsrhs.kind) {
|
||||
// `y + 1` and `1 + y`
|
||||
(&ExprKind::Lit(ref lit), _) if Self::check_lit(lit, 1) => {
|
||||
Self::generate_recommendation(cx, binop, rhsrhs, lhs, Side::RHS)
|
||||
Self::generate_recommendation(cx, binop, rhsrhs, lhs, Side::Rhs)
|
||||
},
|
||||
(_, &ExprKind::Lit(ref lit)) if Self::check_lit(lit, 1) => {
|
||||
Self::generate_recommendation(cx, binop, rhslhs, lhs, Side::RHS)
|
||||
Self::generate_recommendation(cx, binop, rhslhs, lhs, Side::Rhs)
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
@ -97,10 +97,10 @@ impl IntPlusOne {
|
||||
match (&lhslhs.kind, &lhsrhs.kind) {
|
||||
// `1 + x` and `x + 1`
|
||||
(&ExprKind::Lit(ref lit), _) if Self::check_lit(lit, 1) => {
|
||||
Self::generate_recommendation(cx, binop, lhsrhs, rhs, Side::LHS)
|
||||
Self::generate_recommendation(cx, binop, lhsrhs, rhs, Side::Lhs)
|
||||
},
|
||||
(_, &ExprKind::Lit(ref lit)) if Self::check_lit(lit, 1) => {
|
||||
Self::generate_recommendation(cx, binop, lhslhs, rhs, Side::LHS)
|
||||
Self::generate_recommendation(cx, binop, lhslhs, rhs, Side::Lhs)
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
@ -110,11 +110,11 @@ impl IntPlusOne {
|
||||
match (rhskind.node, &rhslhs.kind, &rhsrhs.kind) {
|
||||
// `-1 + y`
|
||||
(BinOpKind::Add, &ExprKind::Lit(ref lit), _) if Self::check_lit(lit, -1) => {
|
||||
Self::generate_recommendation(cx, binop, rhsrhs, lhs, Side::RHS)
|
||||
Self::generate_recommendation(cx, binop, rhsrhs, lhs, Side::Rhs)
|
||||
},
|
||||
// `y - 1`
|
||||
(BinOpKind::Sub, _, &ExprKind::Lit(ref lit)) if Self::check_lit(lit, 1) => {
|
||||
Self::generate_recommendation(cx, binop, rhslhs, lhs, Side::RHS)
|
||||
Self::generate_recommendation(cx, binop, rhslhs, lhs, Side::Rhs)
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
@ -138,8 +138,8 @@ impl IntPlusOne {
|
||||
if let Some(snippet) = snippet_opt(cx, node.span) {
|
||||
if let Some(other_side_snippet) = snippet_opt(cx, other_side.span) {
|
||||
let rec = match side {
|
||||
Side::LHS => Some(format!("{} {} {}", snippet, binop_string, other_side_snippet)),
|
||||
Side::RHS => Some(format!("{} {} {}", other_side_snippet, binop_string, snippet)),
|
||||
Side::Lhs => Some(format!("{} {} {}", snippet, binop_string, other_side_snippet)),
|
||||
Side::Rhs => Some(format!("{} {} {}", other_side_snippet, binop_string, snippet)),
|
||||
};
|
||||
return rec;
|
||||
}
|
||||
|
@ -170,6 +170,7 @@ mod blocks_in_if_conditions;
|
||||
mod booleans;
|
||||
mod bytecount;
|
||||
mod cargo_common_metadata;
|
||||
mod case_sensitive_file_extension_comparisons;
|
||||
mod checked_conversions;
|
||||
mod cognitive_complexity;
|
||||
mod collapsible_if;
|
||||
@ -199,6 +200,7 @@ mod escape;
|
||||
mod eta_reduction;
|
||||
mod eval_order_dependence;
|
||||
mod excessive_bools;
|
||||
mod exhaustive_items;
|
||||
mod exit;
|
||||
mod explicit_write;
|
||||
mod fallible_impl_from;
|
||||
@ -300,6 +302,7 @@ mod redundant_closure_call;
|
||||
mod redundant_else;
|
||||
mod redundant_field_names;
|
||||
mod redundant_pub_crate;
|
||||
mod redundant_slicing;
|
||||
mod redundant_static_lifetimes;
|
||||
mod ref_option_ref;
|
||||
mod reference;
|
||||
@ -339,6 +342,7 @@ mod unused_self;
|
||||
mod unused_unit;
|
||||
mod unwrap;
|
||||
mod unwrap_in_result;
|
||||
mod upper_case_acronyms;
|
||||
mod use_self;
|
||||
mod useless_conversion;
|
||||
mod vec;
|
||||
@ -506,6 +510,10 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||
"clippy::unknown_clippy_lints",
|
||||
"this lint has been integrated into the `unknown_lints` rustc lint",
|
||||
);
|
||||
store.register_removed(
|
||||
"clippy::find_map",
|
||||
"this lint has been replaced by `manual_find_map`, a more specific lint",
|
||||
);
|
||||
// end deprecated lints, do not remove this comment, it’s used in `update_lints`
|
||||
|
||||
// begin register lints, do not remove this comment, it’s used in `update_lints`
|
||||
@ -561,6 +569,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||
&booleans::NONMINIMAL_BOOL,
|
||||
&bytecount::NAIVE_BYTECOUNT,
|
||||
&cargo_common_metadata::CARGO_COMMON_METADATA,
|
||||
&case_sensitive_file_extension_comparisons::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS,
|
||||
&checked_conversions::CHECKED_CONVERSIONS,
|
||||
&cognitive_complexity::COGNITIVE_COMPLEXITY,
|
||||
&collapsible_if::COLLAPSIBLE_ELSE_IF,
|
||||
@ -610,6 +619,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||
&eval_order_dependence::EVAL_ORDER_DEPENDENCE,
|
||||
&excessive_bools::FN_PARAMS_EXCESSIVE_BOOLS,
|
||||
&excessive_bools::STRUCT_EXCESSIVE_BOOLS,
|
||||
&exhaustive_items::EXHAUSTIVE_ENUMS,
|
||||
&exhaustive_items::EXHAUSTIVE_STRUCTS,
|
||||
&exit::EXIT,
|
||||
&explicit_write::EXPLICIT_WRITE,
|
||||
&fallible_impl_from::FALLIBLE_IMPL_FROM,
|
||||
@ -731,11 +742,11 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||
&methods::FILTER_MAP,
|
||||
&methods::FILTER_MAP_NEXT,
|
||||
&methods::FILTER_NEXT,
|
||||
&methods::FIND_MAP,
|
||||
&methods::FLAT_MAP_IDENTITY,
|
||||
&methods::FROM_ITER_INSTEAD_OF_COLLECT,
|
||||
&methods::GET_UNWRAP,
|
||||
&methods::INEFFICIENT_TO_STRING,
|
||||
&methods::INSPECT_FOR_EACH,
|
||||
&methods::INTO_ITER_ON_REF,
|
||||
&methods::ITERATOR_STEP_BY_ZERO,
|
||||
&methods::ITER_CLONED_COLLECT,
|
||||
@ -743,6 +754,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||
&methods::ITER_NTH,
|
||||
&methods::ITER_NTH_ZERO,
|
||||
&methods::ITER_SKIP_NEXT,
|
||||
&methods::MANUAL_FILTER_MAP,
|
||||
&methods::MANUAL_FIND_MAP,
|
||||
&methods::MANUAL_SATURATING_ARITHMETIC,
|
||||
&methods::MAP_COLLECT_RESULT_UNIT,
|
||||
&methods::MAP_FLATTEN,
|
||||
@ -850,6 +863,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||
&redundant_else::REDUNDANT_ELSE,
|
||||
&redundant_field_names::REDUNDANT_FIELD_NAMES,
|
||||
&redundant_pub_crate::REDUNDANT_PUB_CRATE,
|
||||
&redundant_slicing::REDUNDANT_SLICING,
|
||||
&redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES,
|
||||
&ref_option_ref::REF_OPTION_REF,
|
||||
&reference::DEREF_ADDROF,
|
||||
@ -942,6 +956,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||
&unwrap::PANICKING_UNWRAP,
|
||||
&unwrap::UNNECESSARY_UNWRAP,
|
||||
&unwrap_in_result::UNWRAP_IN_RESULT,
|
||||
&upper_case_acronyms::UPPER_CASE_ACRONYMS,
|
||||
&use_self::USE_SELF,
|
||||
&useless_conversion::USELESS_CONVERSION,
|
||||
&vec::USELESS_VEC,
|
||||
@ -981,7 +996,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||
}
|
||||
store.register_late_pass(|| box utils::author::Author);
|
||||
store.register_late_pass(|| box await_holding_invalid::AwaitHolding);
|
||||
store.register_late_pass(|| box serde_api::SerdeAPI);
|
||||
store.register_late_pass(|| box serde_api::SerdeApi);
|
||||
let vec_box_size_threshold = conf.vec_box_size_threshold;
|
||||
store.register_late_pass(move || box types::Types::new(vec_box_size_threshold));
|
||||
store.register_late_pass(|| box booleans::NonminimalBool);
|
||||
@ -1092,6 +1107,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||
store.register_late_pass(|| box eval_order_dependence::EvalOrderDependence);
|
||||
store.register_late_pass(|| box missing_doc::MissingDoc::new());
|
||||
store.register_late_pass(|| box missing_inline::MissingInline);
|
||||
store.register_late_pass(move || box exhaustive_items::ExhaustiveItems);
|
||||
store.register_late_pass(|| box if_let_some_result::OkIfLet);
|
||||
store.register_late_pass(|| box partialeq_ne_impl::PartialEqNeImpl);
|
||||
store.register_late_pass(|| box unused_io_amount::UnusedIoAmount);
|
||||
@ -1172,6 +1188,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||
let enum_variant_name_threshold = conf.enum_variant_name_threshold;
|
||||
store.register_early_pass(move || box enum_variants::EnumVariantNames::new(enum_variant_name_threshold));
|
||||
store.register_early_pass(|| box tabs_in_doc_comments::TabsInDocComments);
|
||||
store.register_early_pass(|| box upper_case_acronyms::UpperCaseAcronyms);
|
||||
store.register_late_pass(|| box default::Default::default());
|
||||
store.register_late_pass(|| box unused_self::UnusedSelf);
|
||||
store.register_late_pass(|| box mutable_debug_assertion::DebugAssertWithMutCall);
|
||||
@ -1229,6 +1246,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||
store.register_late_pass(|| box zero_sized_map_values::ZeroSizedMapValues);
|
||||
store.register_late_pass(|| box vec_init_then_push::VecInitThenPush::default());
|
||||
store.register_late_pass(move || box types::PtrAsPtr::new(msrv));
|
||||
store.register_late_pass(|| box case_sensitive_file_extension_comparisons::CaseSensitiveFileExtensionComparisons);
|
||||
store.register_late_pass(|| box redundant_slicing::RedundantSlicing);
|
||||
|
||||
store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
|
||||
LintId::of(&arithmetic::FLOAT_ARITHMETIC),
|
||||
@ -1239,6 +1258,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||
LintId::of(&create_dir::CREATE_DIR),
|
||||
LintId::of(&dbg_macro::DBG_MACRO),
|
||||
LintId::of(&else_if_without_else::ELSE_IF_WITHOUT_ELSE),
|
||||
LintId::of(&exhaustive_items::EXHAUSTIVE_ENUMS),
|
||||
LintId::of(&exhaustive_items::EXHAUSTIVE_STRUCTS),
|
||||
LintId::of(&exit::EXIT),
|
||||
LintId::of(&float_literal::LOSSY_FLOAT_LITERAL),
|
||||
LintId::of(&implicit_return::IMPLICIT_RETURN),
|
||||
@ -1286,6 +1307,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||
LintId::of(&await_holding_invalid::AWAIT_HOLDING_LOCK),
|
||||
LintId::of(&await_holding_invalid::AWAIT_HOLDING_REFCELL_REF),
|
||||
LintId::of(&bit_mask::VERBOSE_BIT_MASK),
|
||||
LintId::of(&case_sensitive_file_extension_comparisons::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS),
|
||||
LintId::of(&checked_conversions::CHECKED_CONVERSIONS),
|
||||
LintId::of(&copies::SAME_FUNCTIONS_IN_IF_CONDITION),
|
||||
LintId::of(©_iterator::COPY_ITERATOR),
|
||||
@ -1323,7 +1345,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||
LintId::of(&matches::SINGLE_MATCH_ELSE),
|
||||
LintId::of(&methods::FILTER_MAP),
|
||||
LintId::of(&methods::FILTER_MAP_NEXT),
|
||||
LintId::of(&methods::FIND_MAP),
|
||||
LintId::of(&methods::INEFFICIENT_TO_STRING),
|
||||
LintId::of(&methods::MAP_FLATTEN),
|
||||
LintId::of(&methods::MAP_UNWRAP_OR),
|
||||
@ -1509,6 +1530,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||
LintId::of(&methods::FILTER_NEXT),
|
||||
LintId::of(&methods::FLAT_MAP_IDENTITY),
|
||||
LintId::of(&methods::FROM_ITER_INSTEAD_OF_COLLECT),
|
||||
LintId::of(&methods::INSPECT_FOR_EACH),
|
||||
LintId::of(&methods::INTO_ITER_ON_REF),
|
||||
LintId::of(&methods::ITERATOR_STEP_BY_ZERO),
|
||||
LintId::of(&methods::ITER_CLONED_COLLECT),
|
||||
@ -1516,6 +1538,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||
LintId::of(&methods::ITER_NTH),
|
||||
LintId::of(&methods::ITER_NTH_ZERO),
|
||||
LintId::of(&methods::ITER_SKIP_NEXT),
|
||||
LintId::of(&methods::MANUAL_FILTER_MAP),
|
||||
LintId::of(&methods::MANUAL_FIND_MAP),
|
||||
LintId::of(&methods::MANUAL_SATURATING_ARITHMETIC),
|
||||
LintId::of(&methods::MAP_COLLECT_RESULT_UNIT),
|
||||
LintId::of(&methods::NEW_RET_NO_SELF),
|
||||
@ -1589,6 +1613,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||
LintId::of(&redundant_clone::REDUNDANT_CLONE),
|
||||
LintId::of(&redundant_closure_call::REDUNDANT_CLOSURE_CALL),
|
||||
LintId::of(&redundant_field_names::REDUNDANT_FIELD_NAMES),
|
||||
LintId::of(&redundant_slicing::REDUNDANT_SLICING),
|
||||
LintId::of(&redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES),
|
||||
LintId::of(&reference::DEREF_ADDROF),
|
||||
LintId::of(&reference::REF_IN_DEREF),
|
||||
@ -1651,6 +1676,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||
LintId::of(&unused_unit::UNUSED_UNIT),
|
||||
LintId::of(&unwrap::PANICKING_UNWRAP),
|
||||
LintId::of(&unwrap::UNNECESSARY_UNWRAP),
|
||||
LintId::of(&upper_case_acronyms::UPPER_CASE_ACRONYMS),
|
||||
LintId::of(&useless_conversion::USELESS_CONVERSION),
|
||||
LintId::of(&vec::USELESS_VEC),
|
||||
LintId::of(&vec_init_then_push::VEC_INIT_THEN_PUSH),
|
||||
@ -1767,6 +1793,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||
LintId::of(&types::FN_TO_NUMERIC_CAST_WITH_TRUNCATION),
|
||||
LintId::of(&unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME),
|
||||
LintId::of(&unused_unit::UNUSED_UNIT),
|
||||
LintId::of(&upper_case_acronyms::UPPER_CASE_ACRONYMS),
|
||||
LintId::of(&write::PRINTLN_EMPTY_STRING),
|
||||
LintId::of(&write::PRINT_LITERAL),
|
||||
LintId::of(&write::PRINT_WITH_NEWLINE),
|
||||
@ -1808,6 +1835,9 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||
LintId::of(&methods::CLONE_ON_COPY),
|
||||
LintId::of(&methods::FILTER_NEXT),
|
||||
LintId::of(&methods::FLAT_MAP_IDENTITY),
|
||||
LintId::of(&methods::INSPECT_FOR_EACH),
|
||||
LintId::of(&methods::MANUAL_FILTER_MAP),
|
||||
LintId::of(&methods::MANUAL_FIND_MAP),
|
||||
LintId::of(&methods::OPTION_AS_REF_DEREF),
|
||||
LintId::of(&methods::SEARCH_IS_SOME),
|
||||
LintId::of(&methods::SKIP_WHILE_NEXT),
|
||||
@ -1832,6 +1862,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
||||
LintId::of(&ptr_offset_with_cast::PTR_OFFSET_WITH_CAST),
|
||||
LintId::of(&ranges::RANGE_ZIP_WITH_LEN),
|
||||
LintId::of(&redundant_closure_call::REDUNDANT_CLOSURE_CALL),
|
||||
LintId::of(&redundant_slicing::REDUNDANT_SLICING),
|
||||
LintId::of(&reference::DEREF_ADDROF),
|
||||
LintId::of(&reference::REF_IN_DEREF),
|
||||
LintId::of(&repeat_once::REPEAT_ONCE),
|
||||
|
@ -1069,7 +1069,6 @@ fn get_assignments<'a: 'c, 'tcx: 'c, 'c>(
|
||||
) -> impl Iterator<Item = Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>)>> + 'c {
|
||||
// As the `filter` and `map` below do different things, I think putting together
|
||||
// just increases complexity. (cc #3188 and #4193)
|
||||
#[allow(clippy::filter_map)]
|
||||
stmts
|
||||
.iter()
|
||||
.filter_map(move |stmt| match stmt.kind {
|
||||
|
@ -43,8 +43,7 @@ impl LateLintPass<'_> for MainRecursion {
|
||||
|
||||
if_chain! {
|
||||
if let ExprKind::Call(func, _) = &expr.kind;
|
||||
if let ExprKind::Path(path) = &func.kind;
|
||||
if let QPath::Resolved(_, path) = &path;
|
||||
if let ExprKind::Path(QPath::Resolved(_, path)) = &func.kind;
|
||||
if let Some(def_id) = path.res.opt_def_id();
|
||||
if is_entrypoint_fn(cx, def_id);
|
||||
then {
|
||||
|
@ -23,9 +23,6 @@ declare_clippy_lint! {
|
||||
/// ```rust
|
||||
/// let foo: Option<i32> = None;
|
||||
/// foo.map_or(Err("error"), |v| Ok(v));
|
||||
///
|
||||
/// let foo: Option<i32> = None;
|
||||
/// foo.map_or(Err("error"), |v| Ok(v));
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
|
@ -131,7 +131,7 @@ fn reduce_unit_expression<'a>(cx: &LateContext<'_>, expr: &'a hir::Expr<'_>) ->
|
||||
Some(expr.span)
|
||||
},
|
||||
hir::ExprKind::Block(ref block, _) => {
|
||||
match (&block.stmts[..], block.expr.as_ref()) {
|
||||
match (block.stmts, block.expr.as_ref()) {
|
||||
(&[], Some(inner_expr)) => {
|
||||
// If block only contains an expression,
|
||||
// reduce `{ X }` to `X`
|
||||
|
@ -2,10 +2,10 @@ use crate::consts::{constant, miri_to_const, Constant};
|
||||
use crate::utils::sugg::Sugg;
|
||||
use crate::utils::usage::is_unused;
|
||||
use crate::utils::{
|
||||
expr_block, get_arg_name, get_parent_expr, in_macro, indent_of, is_allowed, is_expn_of, is_refutable,
|
||||
is_type_diagnostic_item, is_wild, match_qpath, match_type, match_var, meets_msrv, multispan_sugg, remove_blocks,
|
||||
snippet, snippet_block, snippet_opt, snippet_with_applicability, span_lint_and_help, span_lint_and_note,
|
||||
span_lint_and_sugg, span_lint_and_then,
|
||||
expr_block, get_arg_name, get_parent_expr, implements_trait, in_macro, indent_of, is_allowed, is_expn_of,
|
||||
is_refutable, is_type_diagnostic_item, is_wild, match_qpath, match_type, match_var, meets_msrv, multispan_sugg,
|
||||
peel_hir_pat_refs, peel_mid_ty_refs, peel_n_hir_expr_refs, remove_blocks, snippet, snippet_block, snippet_opt,
|
||||
snippet_with_applicability, span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then,
|
||||
};
|
||||
use crate::utils::{paths, search_same, SpanlessEq, SpanlessHash};
|
||||
use if_chain::if_chain;
|
||||
@ -728,20 +728,60 @@ fn report_single_match_single_pattern(
|
||||
let els_str = els.map_or(String::new(), |els| {
|
||||
format!(" else {}", expr_block(cx, els, None, "..", Some(expr.span)))
|
||||
});
|
||||
|
||||
let (msg, sugg) = if_chain! {
|
||||
let (pat, pat_ref_count) = peel_hir_pat_refs(arms[0].pat);
|
||||
if let PatKind::Path(_) | PatKind::Lit(_) = pat.kind;
|
||||
let (ty, ty_ref_count) = peel_mid_ty_refs(cx.typeck_results().expr_ty(ex));
|
||||
if let Some(trait_id) = cx.tcx.lang_items().structural_peq_trait();
|
||||
if ty.is_integral() || ty.is_char() || ty.is_str() || implements_trait(cx, ty, trait_id, &[]);
|
||||
then {
|
||||
// scrutinee derives PartialEq and the pattern is a constant.
|
||||
let pat_ref_count = match pat.kind {
|
||||
// string literals are already a reference.
|
||||
PatKind::Lit(Expr { kind: ExprKind::Lit(lit), .. }) if lit.node.is_str() => pat_ref_count + 1,
|
||||
_ => pat_ref_count,
|
||||
};
|
||||
// References are only implicitly added to the pattern, so no overflow here.
|
||||
// e.g. will work: match &Some(_) { Some(_) => () }
|
||||
// will not: match Some(_) { &Some(_) => () }
|
||||
let ref_count_diff = ty_ref_count - pat_ref_count;
|
||||
|
||||
// Try to remove address of expressions first.
|
||||
let (ex, removed) = peel_n_hir_expr_refs(ex, ref_count_diff);
|
||||
let ref_count_diff = ref_count_diff - removed;
|
||||
|
||||
let msg = "you seem to be trying to use `match` for an equality check. Consider using `if`";
|
||||
let sugg = format!(
|
||||
"if {} == {}{} {}{}",
|
||||
snippet(cx, ex.span, ".."),
|
||||
// PartialEq for different reference counts may not exist.
|
||||
"&".repeat(ref_count_diff),
|
||||
snippet(cx, arms[0].pat.span, ".."),
|
||||
expr_block(cx, &arms[0].body, None, "..", Some(expr.span)),
|
||||
els_str,
|
||||
);
|
||||
(msg, sugg)
|
||||
} else {
|
||||
let msg = "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`";
|
||||
let sugg = format!(
|
||||
"if let {} = {} {}{}",
|
||||
snippet(cx, arms[0].pat.span, ".."),
|
||||
snippet(cx, ex.span, ".."),
|
||||
expr_block(cx, &arms[0].body, None, "..", Some(expr.span)),
|
||||
els_str,
|
||||
);
|
||||
(msg, sugg)
|
||||
}
|
||||
};
|
||||
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
lint,
|
||||
expr.span,
|
||||
"you seem to be trying to use match for destructuring a single pattern. Consider using `if \
|
||||
let`",
|
||||
msg,
|
||||
"try this",
|
||||
format!(
|
||||
"if let {} = {} {}{}",
|
||||
snippet(cx, arms[0].pat.span, ".."),
|
||||
snippet(cx, ex.span, ".."),
|
||||
expr_block(cx, &arms[0].body, None, "..", Some(expr.span)),
|
||||
els_str,
|
||||
),
|
||||
sugg,
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
}
|
||||
@ -1185,6 +1225,14 @@ fn find_matches_sugg(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr
|
||||
} else {
|
||||
pat
|
||||
};
|
||||
|
||||
// strip potential borrows (#6503), but only if the type is a reference
|
||||
let mut ex_new = ex;
|
||||
if let ExprKind::AddrOf(BorrowKind::Ref, .., ex_inner) = ex.kind {
|
||||
if let ty::Ref(..) = cx.typeck_results().expr_ty(&ex_inner).kind() {
|
||||
ex_new = ex_inner;
|
||||
}
|
||||
};
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
MATCH_LIKE_MATCHES_MACRO,
|
||||
@ -1194,7 +1242,7 @@ fn find_matches_sugg(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr
|
||||
format!(
|
||||
"{}matches!({}, {})",
|
||||
if b0 { "" } else { "!" },
|
||||
snippet_with_applicability(cx, ex.span, "..", &mut applicability),
|
||||
snippet_with_applicability(cx, ex_new.span, "..", &mut applicability),
|
||||
pat_and_guard,
|
||||
),
|
||||
applicability,
|
||||
|
@ -0,0 +1,23 @@
|
||||
use rustc_hir as hir;
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_span::source_map::Span;
|
||||
|
||||
use crate::utils::{match_trait_method, paths, span_lint_and_help};
|
||||
|
||||
use super::INSPECT_FOR_EACH;
|
||||
|
||||
/// lint use of `inspect().for_each()` for `Iterators`
|
||||
pub(super) fn lint<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, inspect_span: Span) {
|
||||
if match_trait_method(cx, expr, &paths::ITERATOR) {
|
||||
let msg = "called `inspect(..).for_each(..)` on an `Iterator`";
|
||||
let hint = "move the code from `inspect(..)` to `for_each(..)` and remove the `inspect(..)`";
|
||||
span_lint_and_help(
|
||||
cx,
|
||||
INSPECT_FOR_EACH,
|
||||
inspect_span.with_hi(expr.span.hi()),
|
||||
msg,
|
||||
None,
|
||||
hint,
|
||||
);
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
mod bind_instead_of_map;
|
||||
mod inefficient_to_string;
|
||||
mod inspect_for_each;
|
||||
mod manual_saturating_arithmetic;
|
||||
mod option_map_unwrap_or;
|
||||
mod unnecessary_filter_map;
|
||||
@ -14,7 +15,8 @@ use if_chain::if_chain;
|
||||
use rustc_ast::ast;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::{TraitItem, TraitItemKind};
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_hir::{Expr, ExprKind, PatKind, QPath, TraitItem, TraitItemKind, UnOp};
|
||||
use rustc_lint::{LateContext, LateLintPass, Lint, LintContext};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_middle::ty::{self, TraitRef, Ty, TyS};
|
||||
@ -449,6 +451,58 @@ declare_clippy_lint! {
|
||||
"using combinations of `filter`, `map`, `filter_map` and `flat_map` which can usually be written as a single method call"
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// **What it does:** Checks for usage of `_.filter(_).map(_)` that can be written more simply
|
||||
/// as `filter_map(_)`.
|
||||
///
|
||||
/// **Why is this bad?** Redundant code in the `filter` and `map` operations is poor style and
|
||||
/// less performant.
|
||||
///
|
||||
/// **Known problems:** None.
|
||||
///
|
||||
/// **Example:**
|
||||
/// Bad:
|
||||
/// ```rust
|
||||
/// (0_i32..10)
|
||||
/// .filter(|n| n.checked_add(1).is_some())
|
||||
/// .map(|n| n.checked_add(1).unwrap());
|
||||
/// ```
|
||||
///
|
||||
/// Good:
|
||||
/// ```rust
|
||||
/// (0_i32..10).filter_map(|n| n.checked_add(1));
|
||||
/// ```
|
||||
pub MANUAL_FILTER_MAP,
|
||||
complexity,
|
||||
"using `_.filter(_).map(_)` in a way that can be written more simply as `filter_map(_)`"
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// **What it does:** Checks for usage of `_.find(_).map(_)` that can be written more simply
|
||||
/// as `find_map(_)`.
|
||||
///
|
||||
/// **Why is this bad?** Redundant code in the `find` and `map` operations is poor style and
|
||||
/// less performant.
|
||||
///
|
||||
/// **Known problems:** None.
|
||||
///
|
||||
/// **Example:**
|
||||
/// Bad:
|
||||
/// ```rust
|
||||
/// (0_i32..10)
|
||||
/// .find(|n| n.checked_add(1).is_some())
|
||||
/// .map(|n| n.checked_add(1).unwrap());
|
||||
/// ```
|
||||
///
|
||||
/// Good:
|
||||
/// ```rust
|
||||
/// (0_i32..10).find_map(|n| n.checked_add(1));
|
||||
/// ```
|
||||
pub MANUAL_FIND_MAP,
|
||||
complexity,
|
||||
"using `_.find(_).map(_)` in a way that can be written more simply as `find_map(_)`"
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// **What it does:** Checks for usage of `_.filter_map(_).next()`.
|
||||
///
|
||||
@ -493,28 +547,6 @@ declare_clippy_lint! {
|
||||
"call to `flat_map` where `flatten` is sufficient"
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// **What it does:** Checks for usage of `_.find(_).map(_)`.
|
||||
///
|
||||
/// **Why is this bad?** Readability, this can be written more concisely as
|
||||
/// `_.find_map(_)`.
|
||||
///
|
||||
/// **Known problems:** Often requires a condition + Option/Iterator creation
|
||||
/// inside the closure.
|
||||
///
|
||||
/// **Example:**
|
||||
/// ```rust
|
||||
/// (0..3).find(|x| *x == 2).map(|x| x * 2);
|
||||
/// ```
|
||||
/// Can be written as
|
||||
/// ```rust
|
||||
/// (0..3).find_map(|x| if x == 2 { Some(x * 2) } else { None });
|
||||
/// ```
|
||||
pub FIND_MAP,
|
||||
pedantic,
|
||||
"using a combination of `find` and `map` can usually be written as a single method call"
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// **What it does:** Checks for an iterator or string search (such as `find()`,
|
||||
/// `position()`, or `rposition()`) followed by a call to `is_some()`.
|
||||
@ -1405,6 +1437,36 @@ declare_clippy_lint! {
|
||||
"use `.collect()` instead of `::from_iter()`"
|
||||
}
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// **What it does:** Checks for usage of `inspect().for_each()`.
|
||||
///
|
||||
/// **Why is this bad?** It is the same as performing the computation
|
||||
/// inside `inspect` at the beginning of the closure in `for_each`.
|
||||
///
|
||||
/// **Known problems:** None.
|
||||
///
|
||||
/// **Example:**
|
||||
///
|
||||
/// ```rust
|
||||
/// [1,2,3,4,5].iter()
|
||||
/// .inspect(|&x| println!("inspect the number: {}", x))
|
||||
/// .for_each(|&x| {
|
||||
/// assert!(x >= 0);
|
||||
/// });
|
||||
/// ```
|
||||
/// Can be written as
|
||||
/// ```rust
|
||||
/// [1,2,3,4,5].iter()
|
||||
/// .for_each(|&x| {
|
||||
/// println!("inspect the number: {}", x);
|
||||
/// assert!(x >= 0);
|
||||
/// });
|
||||
/// ```
|
||||
pub INSPECT_FOR_EACH,
|
||||
complexity,
|
||||
"using `.inspect().for_each()`, which can be replaced with `.for_each()`"
|
||||
}
|
||||
|
||||
pub struct Methods {
|
||||
msrv: Option<RustcVersion>,
|
||||
}
|
||||
@ -1442,9 +1504,10 @@ impl_lint_pass!(Methods => [
|
||||
FILTER_NEXT,
|
||||
SKIP_WHILE_NEXT,
|
||||
FILTER_MAP,
|
||||
MANUAL_FILTER_MAP,
|
||||
MANUAL_FIND_MAP,
|
||||
FILTER_MAP_NEXT,
|
||||
FLAT_MAP_IDENTITY,
|
||||
FIND_MAP,
|
||||
MAP_FLATTEN,
|
||||
ITERATOR_STEP_BY_ZERO,
|
||||
ITER_NEXT_SLICE,
|
||||
@ -1467,6 +1530,7 @@ impl_lint_pass!(Methods => [
|
||||
UNNECESSARY_LAZY_EVALUATIONS,
|
||||
MAP_COLLECT_RESULT_UNIT,
|
||||
FROM_ITER_INSTEAD_OF_COLLECT,
|
||||
INSPECT_FOR_EACH,
|
||||
]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for Methods {
|
||||
@ -1508,10 +1572,10 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
|
||||
["next", "filter"] => lint_filter_next(cx, expr, arg_lists[1]),
|
||||
["next", "skip_while"] => lint_skip_while_next(cx, expr, arg_lists[1]),
|
||||
["next", "iter"] => lint_iter_next(cx, expr, arg_lists[1]),
|
||||
["map", "filter"] => lint_filter_map(cx, expr, arg_lists[1], arg_lists[0]),
|
||||
["map", "filter"] => lint_filter_map(cx, expr, false),
|
||||
["map", "filter_map"] => lint_filter_map_map(cx, expr, arg_lists[1], arg_lists[0]),
|
||||
["next", "filter_map"] => lint_filter_map_next(cx, expr, arg_lists[1], self.msrv.as_ref()),
|
||||
["map", "find"] => lint_find_map(cx, expr, arg_lists[1], arg_lists[0]),
|
||||
["map", "find"] => lint_filter_map(cx, expr, true),
|
||||
["flat_map", "filter"] => lint_filter_flat_map(cx, expr, arg_lists[1], arg_lists[0]),
|
||||
["flat_map", "filter_map"] => lint_filter_map_flat_map(cx, expr, arg_lists[1], arg_lists[0]),
|
||||
["flat_map", ..] => lint_flat_map_identity(cx, expr, arg_lists[0], method_spans[0]),
|
||||
@ -1553,6 +1617,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
|
||||
["get_or_insert_with", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "get_or_insert"),
|
||||
["ok_or_else", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "ok_or"),
|
||||
["collect", "map"] => lint_map_collect(cx, expr, arg_lists[1], arg_lists[0]),
|
||||
["for_each", "inspect"] => inspect_for_each::lint(cx, expr, method_spans[1]),
|
||||
_ => {},
|
||||
}
|
||||
|
||||
@ -2955,18 +3020,79 @@ fn lint_skip_while_next<'tcx>(
|
||||
}
|
||||
}
|
||||
|
||||
/// lint use of `filter().map()` for `Iterators`
|
||||
fn lint_filter_map<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
expr: &'tcx hir::Expr<'_>,
|
||||
_filter_args: &'tcx [hir::Expr<'_>],
|
||||
_map_args: &'tcx [hir::Expr<'_>],
|
||||
) {
|
||||
// lint if caller of `.filter().map()` is an Iterator
|
||||
if match_trait_method(cx, expr, &paths::ITERATOR) {
|
||||
let msg = "called `filter(..).map(..)` on an `Iterator`";
|
||||
let hint = "this is more succinctly expressed by calling `.filter_map(..)` instead";
|
||||
span_lint_and_help(cx, FILTER_MAP, expr.span, msg, None, hint);
|
||||
/// lint use of `filter().map()` or `find().map()` for `Iterators`
|
||||
fn lint_filter_map<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, is_find: bool) {
|
||||
if_chain! {
|
||||
if let ExprKind::MethodCall(_, _, [map_recv, map_arg], map_span) = expr.kind;
|
||||
if let ExprKind::MethodCall(_, _, [_, filter_arg], filter_span) = map_recv.kind;
|
||||
if match_trait_method(cx, map_recv, &paths::ITERATOR);
|
||||
|
||||
// filter(|x| ...is_some())...
|
||||
if let ExprKind::Closure(_, _, filter_body_id, ..) = filter_arg.kind;
|
||||
let filter_body = cx.tcx.hir().body(filter_body_id);
|
||||
if let [filter_param] = filter_body.params;
|
||||
// optional ref pattern: `filter(|&x| ..)`
|
||||
let (filter_pat, is_filter_param_ref) = if let PatKind::Ref(ref_pat, _) = filter_param.pat.kind {
|
||||
(ref_pat, true)
|
||||
} else {
|
||||
(filter_param.pat, false)
|
||||
};
|
||||
// closure ends with is_some() or is_ok()
|
||||
if let PatKind::Binding(_, filter_param_id, _, None) = filter_pat.kind;
|
||||
if let ExprKind::MethodCall(path, _, [filter_arg], _) = filter_body.value.kind;
|
||||
if let Some(opt_ty) = cx.typeck_results().expr_ty(filter_arg).ty_adt_def();
|
||||
if let Some(is_result) = if cx.tcx.is_diagnostic_item(sym::option_type, opt_ty.did) {
|
||||
Some(false)
|
||||
} else if cx.tcx.is_diagnostic_item(sym::result_type, opt_ty.did) {
|
||||
Some(true)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
if path.ident.name.as_str() == if is_result { "is_ok" } else { "is_some" };
|
||||
|
||||
// ...map(|x| ...unwrap())
|
||||
if let ExprKind::Closure(_, _, map_body_id, ..) = map_arg.kind;
|
||||
let map_body = cx.tcx.hir().body(map_body_id);
|
||||
if let [map_param] = map_body.params;
|
||||
if let PatKind::Binding(_, map_param_id, map_param_ident, None) = map_param.pat.kind;
|
||||
// closure ends with expect() or unwrap()
|
||||
if let ExprKind::MethodCall(seg, _, [map_arg, ..], _) = map_body.value.kind;
|
||||
if matches!(seg.ident.name, sym::expect | sym::unwrap | sym::unwrap_or);
|
||||
|
||||
let eq_fallback = |a: &Expr<'_>, b: &Expr<'_>| {
|
||||
// in `filter(|x| ..)`, replace `*x` with `x`
|
||||
let a_path = if_chain! {
|
||||
if !is_filter_param_ref;
|
||||
if let ExprKind::Unary(UnOp::UnDeref, expr_path) = a.kind;
|
||||
then { expr_path } else { a }
|
||||
};
|
||||
// let the filter closure arg and the map closure arg be equal
|
||||
if_chain! {
|
||||
if let ExprKind::Path(QPath::Resolved(None, a_path)) = a_path.kind;
|
||||
if let ExprKind::Path(QPath::Resolved(None, b_path)) = b.kind;
|
||||
if a_path.res == Res::Local(filter_param_id);
|
||||
if b_path.res == Res::Local(map_param_id);
|
||||
if TyS::same_type(cx.typeck_results().expr_ty_adjusted(a), cx.typeck_results().expr_ty_adjusted(b));
|
||||
then {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
};
|
||||
if SpanlessEq::new(cx).expr_fallback(eq_fallback).eq_expr(filter_arg, map_arg);
|
||||
then {
|
||||
let span = filter_span.to(map_span);
|
||||
let (filter_name, lint) = if is_find {
|
||||
("find", MANUAL_FIND_MAP)
|
||||
} else {
|
||||
("filter", MANUAL_FILTER_MAP)
|
||||
};
|
||||
let msg = format!("`{}(..).map(..)` can be simplified as `{0}_map(..)`", filter_name);
|
||||
let to_opt = if is_result { ".ok()" } else { "" };
|
||||
let sugg = format!("{}_map(|{}| {}{})", filter_name, map_param_ident,
|
||||
snippet(cx, map_arg.span, ".."), to_opt);
|
||||
span_lint_and_sugg(cx, lint, span, &msg, "try", sugg, Applicability::MachineApplicable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3004,21 +3130,6 @@ fn lint_filter_map_next<'tcx>(
|
||||
}
|
||||
}
|
||||
|
||||
/// lint use of `find().map()` for `Iterators`
|
||||
fn lint_find_map<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
expr: &'tcx hir::Expr<'_>,
|
||||
_find_args: &'tcx [hir::Expr<'_>],
|
||||
map_args: &'tcx [hir::Expr<'_>],
|
||||
) {
|
||||
// lint if caller of `.filter().map()` is an Iterator
|
||||
if match_trait_method(cx, &map_args[0], &paths::ITERATOR) {
|
||||
let msg = "called `find(..).map(..)` on an `Iterator`";
|
||||
let hint = "this is more succinctly expressed by calling `.find_map(..)` instead";
|
||||
span_lint_and_help(cx, FIND_MAP, expr.span, msg, None, hint);
|
||||
}
|
||||
}
|
||||
|
||||
/// lint use of `filter_map().map()` for `Iterators`
|
||||
fn lint_filter_map_map<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
@ -3026,7 +3137,7 @@ fn lint_filter_map_map<'tcx>(
|
||||
_filter_args: &'tcx [hir::Expr<'_>],
|
||||
_map_args: &'tcx [hir::Expr<'_>],
|
||||
) {
|
||||
// lint if caller of `.filter().map()` is an Iterator
|
||||
// lint if caller of `.filter_map().map()` is an Iterator
|
||||
if match_trait_method(cx, expr, &paths::ITERATOR) {
|
||||
let msg = "called `filter_map(..).map(..)` on an `Iterator`";
|
||||
let hint = "this is more succinctly expressed by only calling `.filter_map(..)` instead";
|
||||
|
@ -117,9 +117,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
|
||||
.filter_map(|obligation| {
|
||||
// Note that we do not want to deal with qualified predicates here.
|
||||
match obligation.predicate.kind().no_bound_vars() {
|
||||
Some(ty::PredicateKind::Trait(pred, _)) if pred.def_id() != sized_trait => {
|
||||
Some(pred)
|
||||
},
|
||||
Some(ty::PredicateKind::Trait(pred, _)) if pred.def_id() != sized_trait => Some(pred),
|
||||
_ => None,
|
||||
}
|
||||
})
|
||||
|
@ -199,6 +199,10 @@ impl<'a, 'tcx, 'b> SimilarNamesNameVisitor<'a, 'tcx, 'b> {
|
||||
);
|
||||
return;
|
||||
}
|
||||
if interned_name.starts_with('_') {
|
||||
// these bindings are typically unused or represent an ignored portion of a destructuring pattern
|
||||
return;
|
||||
}
|
||||
let count = interned_name.chars().count();
|
||||
if count < 3 {
|
||||
if count == 1 {
|
||||
|
@ -263,8 +263,7 @@ fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_id:
|
||||
} else if match_type(cx, ty, &paths::COW) {
|
||||
if_chain! {
|
||||
if let TyKind::Rptr(_, MutTy { ref ty, ..} ) = arg.kind;
|
||||
if let TyKind::Path(ref path) = ty.kind;
|
||||
if let QPath::Resolved(None, ref pp) = *path;
|
||||
if let TyKind::Path(QPath::Resolved(None, ref pp)) = ty.kind;
|
||||
if let [ref bx] = *pp.segments;
|
||||
if let Some(ref params) = bx.args;
|
||||
if !params.parenthesized;
|
||||
|
67
src/tools/clippy/clippy_lints/src/redundant_slicing.rs
Normal file
67
src/tools/clippy/clippy_lints/src/redundant_slicing.rs
Normal file
@ -0,0 +1,67 @@
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, ExprKind, LangItem};
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
||||
use rustc_middle::{lint::in_external_macro, ty::TyS};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
|
||||
use crate::utils::{is_type_lang_item, snippet_with_applicability, span_lint_and_sugg};
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// **What it does:** Checks for redundant slicing expressions which use the full range, and
|
||||
/// do not change the type.
|
||||
///
|
||||
/// **Why is this bad?** It unnecessarily adds complexity to the expression.
|
||||
///
|
||||
/// **Known problems:** If the type being sliced has an implementation of `Index<RangeFull>`
|
||||
/// that actually changes anything then it can't be removed. However, this would be surprising
|
||||
/// to people reading the code and should have a note with it.
|
||||
///
|
||||
/// **Example:**
|
||||
///
|
||||
/// ```ignore
|
||||
/// fn get_slice(x: &[u32]) -> &[u32] {
|
||||
/// &x[..]
|
||||
/// }
|
||||
/// ```
|
||||
/// Use instead:
|
||||
/// ```ignore
|
||||
/// fn get_slice(x: &[u32]) -> &[u32] {
|
||||
/// x
|
||||
/// }
|
||||
/// ```
|
||||
pub REDUNDANT_SLICING,
|
||||
complexity,
|
||||
"redundant slicing of the whole range of a type"
|
||||
}
|
||||
|
||||
declare_lint_pass!(RedundantSlicing => [REDUNDANT_SLICING]);
|
||||
|
||||
impl LateLintPass<'_> for RedundantSlicing {
|
||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
if in_external_macro(cx.sess(), expr.span) {
|
||||
return;
|
||||
}
|
||||
|
||||
if_chain! {
|
||||
if let ExprKind::AddrOf(_, _, addressee) = expr.kind;
|
||||
if let ExprKind::Index(indexed, range) = addressee.kind;
|
||||
if is_type_lang_item(cx, cx.typeck_results().expr_ty_adjusted(range), LangItem::RangeFull);
|
||||
if TyS::same_type(cx.typeck_results().expr_ty(expr), cx.typeck_results().expr_ty(indexed));
|
||||
then {
|
||||
let mut app = Applicability::MachineApplicable;
|
||||
let hint = snippet_with_applicability(cx, indexed.span, "..", &mut app).into_owned();
|
||||
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
REDUNDANT_SLICING,
|
||||
expr.span,
|
||||
"redundant slicing of the whole range",
|
||||
"use the original slice instead",
|
||||
hint,
|
||||
app,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
use crate::utils::sugg::Sugg;
|
||||
use crate::utils::{in_macro, snippet_opt, snippet_with_applicability, span_lint_and_sugg};
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::ast::{Expr, ExprKind, Mutability, UnOp};
|
||||
@ -110,6 +111,12 @@ declare_clippy_lint! {
|
||||
/// let point = Point(30, 20);
|
||||
/// let x = (&point).0;
|
||||
/// ```
|
||||
/// Use instead:
|
||||
/// ```rust
|
||||
/// # struct Point(u32, u32);
|
||||
/// # let point = Point(30, 20);
|
||||
/// let x = point.0;
|
||||
/// ```
|
||||
pub REF_IN_DEREF,
|
||||
complexity,
|
||||
"Use of reference in auto dereference expression."
|
||||
@ -124,14 +131,19 @@ impl EarlyLintPass for RefInDeref {
|
||||
if let ExprKind::Paren(ref parened) = object.kind;
|
||||
if let ExprKind::AddrOf(_, _, ref inner) = parened.kind;
|
||||
then {
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let applicability = if inner.span.from_expansion() {
|
||||
Applicability::MaybeIncorrect
|
||||
} else {
|
||||
Applicability::MachineApplicable
|
||||
};
|
||||
let sugg = Sugg::ast(cx, inner, "_").maybe_par();
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
REF_IN_DEREF,
|
||||
object.span,
|
||||
"creating a reference that is immediately dereferenced",
|
||||
"try this",
|
||||
snippet_with_applicability(cx, inner.span, "_", &mut applicability).to_string(),
|
||||
sugg.to_string(),
|
||||
applicability,
|
||||
);
|
||||
}
|
||||
|
@ -131,7 +131,16 @@ impl<'tcx> LateLintPass<'tcx> for Return {
|
||||
_: HirId,
|
||||
) {
|
||||
match kind {
|
||||
FnKind::Closure(_) => check_final_expr(cx, &body.value, Some(body.value.span), RetReplacement::Empty),
|
||||
FnKind::Closure(_) => {
|
||||
// when returning without value in closure, replace this `return`
|
||||
// with an empty block to prevent invalid suggestion (see #6501)
|
||||
let replacement = if let ExprKind::Ret(None) = &body.value.kind {
|
||||
RetReplacement::Block
|
||||
} else {
|
||||
RetReplacement::Empty
|
||||
};
|
||||
check_final_expr(cx, &body.value, Some(body.value.span), replacement)
|
||||
},
|
||||
FnKind::ItemFn(..) | FnKind::Method(..) => {
|
||||
if let ExprKind::Block(ref block, _) = body.value.kind {
|
||||
check_block_return(cx, block);
|
||||
|
@ -18,9 +18,9 @@ declare_clippy_lint! {
|
||||
"various things that will negatively affect your serde experience"
|
||||
}
|
||||
|
||||
declare_lint_pass!(SerdeAPI => [SERDE_API_MISUSE]);
|
||||
declare_lint_pass!(SerdeApi => [SERDE_API_MISUSE]);
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for SerdeAPI {
|
||||
impl<'tcx> LateLintPass<'tcx> for SerdeApi {
|
||||
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
|
||||
if let ItemKind::Impl(Impl {
|
||||
of_trait: Some(ref trait_ref),
|
||||
|
@ -35,10 +35,11 @@ declare_clippy_lint! {
|
||||
|
||||
declare_lint_pass!(SizeOfInElementCount => [SIZE_OF_IN_ELEMENT_COUNT]);
|
||||
|
||||
fn get_size_of_ty(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<Ty<'tcx>> {
|
||||
fn get_size_of_ty(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, inverted: bool) -> Option<Ty<'tcx>> {
|
||||
match expr.kind {
|
||||
ExprKind::Call(count_func, _func_args) => {
|
||||
if_chain! {
|
||||
if !inverted;
|
||||
if let ExprKind::Path(ref count_func_qpath) = count_func.kind;
|
||||
if let Some(def_id) = cx.qpath_res(count_func_qpath, count_func.hir_id).opt_def_id();
|
||||
if match_def_path(cx, def_id, &paths::MEM_SIZE_OF)
|
||||
@ -50,10 +51,13 @@ fn get_size_of_ty(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<Ty<'tc
|
||||
}
|
||||
}
|
||||
},
|
||||
ExprKind::Binary(op, left, right) if BinOpKind::Mul == op.node || BinOpKind::Div == op.node => {
|
||||
get_size_of_ty(cx, left).or_else(|| get_size_of_ty(cx, right))
|
||||
ExprKind::Binary(op, left, right) if BinOpKind::Mul == op.node => {
|
||||
get_size_of_ty(cx, left, inverted).or_else(|| get_size_of_ty(cx, right, inverted))
|
||||
},
|
||||
ExprKind::Cast(expr, _) => get_size_of_ty(cx, expr),
|
||||
ExprKind::Binary(op, left, right) if BinOpKind::Div == op.node => {
|
||||
get_size_of_ty(cx, left, inverted).or_else(|| get_size_of_ty(cx, right, !inverted))
|
||||
},
|
||||
ExprKind::Cast(expr, _) => get_size_of_ty(cx, expr, inverted),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@ -128,7 +132,7 @@ impl<'tcx> LateLintPass<'tcx> for SizeOfInElementCount {
|
||||
|
||||
// Find a size_of call in the count parameter expression and
|
||||
// check that it's the same type
|
||||
if let Some(ty_used_for_size_of) = get_size_of_ty(cx, count_expr);
|
||||
if let Some(ty_used_for_size_of) = get_size_of_ty(cx, count_expr, false);
|
||||
if TyS::same_type(pointee_ty, ty_used_for_size_of);
|
||||
then {
|
||||
span_lint_and_help(
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::utils::{is_slice_of_primitives, span_lint_and_sugg, sugg::Sugg};
|
||||
use crate::utils::{is_slice_of_primitives, span_lint_and_then, sugg::Sugg};
|
||||
|
||||
use if_chain::if_chain;
|
||||
|
||||
@ -107,25 +107,32 @@ fn detect_stable_sort_primitive(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option
|
||||
impl LateLintPass<'_> for StableSortPrimitive {
|
||||
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||
if let Some(detection) = detect_stable_sort_primitive(cx, expr) {
|
||||
span_lint_and_sugg(
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
STABLE_SORT_PRIMITIVE,
|
||||
expr.span,
|
||||
format!(
|
||||
"used {} instead of {} to sort primitive type `{}`",
|
||||
"used `{}` on primitive type `{}`",
|
||||
detection.method.stable_name(),
|
||||
detection.method.unstable_name(),
|
||||
detection.slice_type,
|
||||
)
|
||||
.as_str(),
|
||||
"try",
|
||||
format!(
|
||||
"{}.{}({})",
|
||||
detection.slice_name,
|
||||
detection.method.unstable_name(),
|
||||
detection.method_args
|
||||
),
|
||||
Applicability::MachineApplicable,
|
||||
|diag| {
|
||||
diag.span_suggestion(
|
||||
expr.span,
|
||||
"try",
|
||||
format!(
|
||||
"{}.{}({})",
|
||||
detection.slice_name,
|
||||
detection.method.unstable_name(),
|
||||
detection.method_args,
|
||||
),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
diag.note(
|
||||
"an unstable sort would perform faster without any observable difference for this data type",
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
93
src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs
Normal file
93
src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs
Normal file
@ -0,0 +1,93 @@
|
||||
use crate::utils::span_lint_and_sugg;
|
||||
use if_chain::if_chain;
|
||||
use itertools::Itertools;
|
||||
use rustc_ast::ast::{Item, ItemKind, Variant};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
|
||||
use rustc_middle::lint::in_external_macro;
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_span::symbol::Ident;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// **What it does:** Checks for camel case name containing a capitalized acronym.
|
||||
///
|
||||
/// **Why is this bad?** In CamelCase, acronyms count as one word.
|
||||
/// See [naming conventions](https://rust-lang.github.io/api-guidelines/naming.html#casing-conforms-to-rfc-430-c-case)
|
||||
/// for more.
|
||||
///
|
||||
/// **Known problems:** When two acronyms are contiguous, the lint can't tell where
|
||||
/// the first acronym ends and the second starts, so it suggests to lowercase all of
|
||||
/// the letters in the second acronym.
|
||||
///
|
||||
/// **Example:**
|
||||
///
|
||||
/// ```rust
|
||||
/// struct HTTPResponse;
|
||||
/// ```
|
||||
/// Use instead:
|
||||
/// ```rust
|
||||
/// struct HttpResponse;
|
||||
/// ```
|
||||
pub UPPER_CASE_ACRONYMS,
|
||||
style,
|
||||
"capitalized acronyms are against the naming convention"
|
||||
}
|
||||
|
||||
declare_lint_pass!(UpperCaseAcronyms => [UPPER_CASE_ACRONYMS]);
|
||||
|
||||
fn correct_ident(ident: &str) -> String {
|
||||
let ident = ident.chars().rev().collect::<String>();
|
||||
let fragments = ident
|
||||
.split_inclusive(|x: char| !x.is_ascii_lowercase())
|
||||
.rev()
|
||||
.map(|x| x.chars().rev().collect::<String>());
|
||||
|
||||
let mut ident = fragments.clone().next().unwrap();
|
||||
for (ref prev, ref curr) in fragments.tuple_windows() {
|
||||
if [prev, curr]
|
||||
.iter()
|
||||
.all(|s| s.len() == 1 && s.chars().next().unwrap().is_ascii_uppercase())
|
||||
{
|
||||
ident.push_str(&curr.to_ascii_lowercase());
|
||||
} else {
|
||||
ident.push_str(curr);
|
||||
}
|
||||
}
|
||||
ident
|
||||
}
|
||||
|
||||
fn check_ident(cx: &EarlyContext<'_>, ident: &Ident) {
|
||||
let span = ident.span;
|
||||
let ident = &ident.as_str();
|
||||
let corrected = correct_ident(ident);
|
||||
if ident != &corrected {
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
UPPER_CASE_ACRONYMS,
|
||||
span,
|
||||
&format!("name `{}` contains a capitalized acronym", ident),
|
||||
"consider making the acronym lowercase, except the initial letter",
|
||||
corrected,
|
||||
Applicability::MaybeIncorrect,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl EarlyLintPass for UpperCaseAcronyms {
|
||||
fn check_item(&mut self, cx: &EarlyContext<'_>, it: &Item) {
|
||||
if_chain! {
|
||||
if !in_external_macro(cx.sess(), it.span);
|
||||
if matches!(
|
||||
it.kind,
|
||||
ItemKind::TyAlias(..) | ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Trait(..)
|
||||
);
|
||||
then {
|
||||
check_ident(cx, &it.ident);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_variant(&mut self, cx: &EarlyContext<'_>, v: &Variant) {
|
||||
check_ident(cx, &v.ident);
|
||||
}
|
||||
}
|
@ -127,6 +127,7 @@ define_Conf! {
|
||||
"OAuth", "GraphQL",
|
||||
"OCaml",
|
||||
"OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap",
|
||||
"WebGL",
|
||||
"TensorFlow",
|
||||
"TrueType",
|
||||
"iOS", "macOS",
|
||||
|
@ -186,8 +186,6 @@ pub fn span_lint_hir_and_then(
|
||||
/// |
|
||||
/// = note: `-D fold-any` implied by `-D warnings`
|
||||
/// ```
|
||||
|
||||
#[allow(clippy::unknown_clippy_lints)]
|
||||
#[cfg_attr(feature = "internal-lints", allow(clippy::collapsible_span_lint_calls))]
|
||||
pub fn span_lint_and_sugg<'a, T: LintContext>(
|
||||
cx: &'a T,
|
||||
|
@ -158,8 +158,7 @@ pub fn for_loop<'tcx>(
|
||||
/// `while cond { body }` becomes `(cond, body)`.
|
||||
pub fn while_loop<'tcx>(expr: &'tcx hir::Expr<'tcx>) -> Option<(&'tcx hir::Expr<'tcx>, &'tcx hir::Expr<'tcx>)> {
|
||||
if_chain! {
|
||||
if let hir::ExprKind::Loop(block, _, hir::LoopSource::While, _) = &expr.kind;
|
||||
if let hir::Block { expr: Some(expr), .. } = &**block;
|
||||
if let hir::ExprKind::Loop(hir::Block { expr: Some(expr), .. }, _, hir::LoopSource::While, _) = &expr.kind;
|
||||
if let hir::ExprKind::Match(cond, arms, hir::MatchSource::WhileDesugar) = &expr.kind;
|
||||
if let hir::ExprKind::DropTemps(cond) = &cond.kind;
|
||||
if let [hir::Arm { body, .. }, ..] = &arms[..];
|
||||
|
@ -24,6 +24,7 @@ pub struct SpanlessEq<'a, 'tcx> {
|
||||
cx: &'a LateContext<'tcx>,
|
||||
maybe_typeck_results: Option<&'tcx TypeckResults<'tcx>>,
|
||||
allow_side_effects: bool,
|
||||
expr_fallback: Option<Box<dyn Fn(&Expr<'_>, &Expr<'_>) -> bool + 'a>>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> SpanlessEq<'a, 'tcx> {
|
||||
@ -32,6 +33,7 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> {
|
||||
cx,
|
||||
maybe_typeck_results: cx.maybe_typeck_results(),
|
||||
allow_side_effects: true,
|
||||
expr_fallback: None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -43,6 +45,13 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expr_fallback(self, expr_fallback: impl Fn(&Expr<'_>, &Expr<'_>) -> bool + 'a) -> Self {
|
||||
Self {
|
||||
expr_fallback: Some(Box::new(expr_fallback)),
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks whether two statements are the same.
|
||||
pub fn eq_stmt(&mut self, left: &Stmt<'_>, right: &Stmt<'_>) -> bool {
|
||||
match (&left.kind, &right.kind) {
|
||||
@ -81,7 +90,7 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
match (&reduce_exprkind(&left.kind), &reduce_exprkind(&right.kind)) {
|
||||
let is_eq = match (&reduce_exprkind(&left.kind), &reduce_exprkind(&right.kind)) {
|
||||
(&ExprKind::AddrOf(lb, l_mut, ref le), &ExprKind::AddrOf(rb, r_mut, ref re)) => {
|
||||
lb == rb && l_mut == r_mut && self.eq_expr(le, re)
|
||||
},
|
||||
@ -158,7 +167,8 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> {
|
||||
(&ExprKind::Array(l), &ExprKind::Array(r)) => self.eq_exprs(l, r),
|
||||
(&ExprKind::DropTemps(ref le), &ExprKind::DropTemps(ref re)) => self.eq_expr(le, re),
|
||||
_ => false,
|
||||
}
|
||||
};
|
||||
is_eq || self.expr_fallback.as_ref().map_or(false, |f| f(left, right))
|
||||
}
|
||||
|
||||
fn eq_exprs(&mut self, left: &[Expr<'_>], right: &[Expr<'_>]) -> bool {
|
||||
|
@ -31,7 +31,6 @@ pub use self::hir_utils::{both, eq_expr_value, over, SpanlessEq, SpanlessHash};
|
||||
use std::borrow::Cow;
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::hash::BuildHasherDefault;
|
||||
use std::mem;
|
||||
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::ast::{self, Attribute, LitKind};
|
||||
@ -39,7 +38,7 @@ use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
|
||||
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
|
||||
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
|
||||
use rustc_hir::Node;
|
||||
use rustc_hir::{
|
||||
@ -48,6 +47,7 @@ use rustc_hir::{
|
||||
};
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_lint::{LateContext, Level, Lint, LintContext};
|
||||
use rustc_middle::hir::exports::Export;
|
||||
use rustc_middle::hir::map::Map;
|
||||
use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
|
||||
use rustc_middle::ty::{self, layout::IntegerExt, Ty, TyCtxt, TypeFoldable};
|
||||
@ -308,65 +308,43 @@ pub fn match_path_ast(path: &ast::Path, segments: &[&str]) -> bool {
|
||||
}
|
||||
|
||||
/// Gets the definition associated to a path.
|
||||
pub fn path_to_res(cx: &LateContext<'_>, path: &[&str]) -> Option<def::Res> {
|
||||
let crates = cx.tcx.crates();
|
||||
let krate = crates
|
||||
.iter()
|
||||
.find(|&&krate| cx.tcx.crate_name(krate).as_str() == path[0]);
|
||||
if let Some(krate) = krate {
|
||||
let krate = DefId {
|
||||
krate: *krate,
|
||||
index: CRATE_DEF_INDEX,
|
||||
};
|
||||
let mut current_item = None;
|
||||
let mut items = cx.tcx.item_children(krate);
|
||||
let mut path_it = path.iter().skip(1).peekable();
|
||||
|
||||
loop {
|
||||
let segment = match path_it.next() {
|
||||
Some(segment) => segment,
|
||||
None => return None,
|
||||
};
|
||||
|
||||
// `get_def_path` seems to generate these empty segments for extern blocks.
|
||||
// We can just ignore them.
|
||||
if segment.is_empty() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let result = SmallVec::<[_; 8]>::new();
|
||||
for item in mem::replace(&mut items, cx.tcx.arena.alloc_slice(&result)).iter() {
|
||||
if item.ident.name.as_str() == *segment {
|
||||
if path_it.peek().is_none() {
|
||||
return Some(item.res);
|
||||
}
|
||||
|
||||
current_item = Some(item);
|
||||
items = cx.tcx.item_children(item.res.def_id());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// The segment isn't a child_item.
|
||||
// Try to find it under an inherent impl.
|
||||
if_chain! {
|
||||
if path_it.peek().is_none();
|
||||
if let Some(current_item) = current_item;
|
||||
let item_def_id = current_item.res.def_id();
|
||||
if cx.tcx.def_kind(item_def_id) == DefKind::Struct;
|
||||
then {
|
||||
// Bad `find_map` suggestion. See #4193.
|
||||
#[allow(clippy::find_map)]
|
||||
return cx.tcx.inherent_impls(item_def_id).iter()
|
||||
.flat_map(|&impl_def_id| cx.tcx.item_children(impl_def_id))
|
||||
.find(|item| item.ident.name.as_str() == *segment)
|
||||
.map(|item| item.res);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
None
|
||||
#[allow(clippy::shadow_unrelated)] // false positive #6563
|
||||
pub fn path_to_res(cx: &LateContext<'_>, path: &[&str]) -> Option<Res> {
|
||||
fn item_child_by_name<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, name: &str) -> Option<&'tcx Export<HirId>> {
|
||||
tcx.item_children(def_id)
|
||||
.iter()
|
||||
.find(|item| item.ident.name.as_str() == name)
|
||||
}
|
||||
|
||||
let (krate, first, path) = match *path {
|
||||
[krate, first, ref path @ ..] => (krate, first, path),
|
||||
_ => return None,
|
||||
};
|
||||
let tcx = cx.tcx;
|
||||
let crates = tcx.crates();
|
||||
let krate = crates.iter().find(|&&num| tcx.crate_name(num).as_str() == krate)?;
|
||||
let first = item_child_by_name(tcx, krate.as_def_id(), first)?;
|
||||
let last = path
|
||||
.iter()
|
||||
.copied()
|
||||
// `get_def_path` seems to generate these empty segments for extern blocks.
|
||||
// We can just ignore them.
|
||||
.filter(|segment| !segment.is_empty())
|
||||
// for each segment, find the child item
|
||||
.try_fold(first, |item, segment| {
|
||||
let def_id = item.res.def_id();
|
||||
if let Some(item) = item_child_by_name(tcx, def_id, segment) {
|
||||
Some(item)
|
||||
} else if matches!(item.res, Res::Def(DefKind::Enum | DefKind::Struct, _)) {
|
||||
// it is not a child item so check inherent impl items
|
||||
tcx.inherent_impls(def_id)
|
||||
.iter()
|
||||
.find_map(|&impl_def_id| item_child_by_name(tcx, impl_def_id, segment))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})?;
|
||||
Some(last.res)
|
||||
}
|
||||
|
||||
/// Convenience function to get the `DefId` of a trait by path.
|
||||
@ -1134,8 +1112,7 @@ pub fn is_self(slf: &Param<'_>) -> bool {
|
||||
|
||||
pub fn is_self_ty(slf: &hir::Ty<'_>) -> bool {
|
||||
if_chain! {
|
||||
if let TyKind::Path(ref qp) = slf.kind;
|
||||
if let QPath::Resolved(None, ref path) = *qp;
|
||||
if let TyKind::Path(QPath::Resolved(None, ref path)) = slf.kind;
|
||||
if let Res::SelfTy(..) = path.res;
|
||||
then {
|
||||
return true
|
||||
@ -1655,6 +1632,44 @@ where
|
||||
match_expr_list
|
||||
}
|
||||
|
||||
/// Peels off all references on the pattern. Returns the underlying pattern and the number of
|
||||
/// references removed.
|
||||
pub fn peel_hir_pat_refs(pat: &'a Pat<'a>) -> (&'a Pat<'a>, usize) {
|
||||
fn peel(pat: &'a Pat<'a>, count: usize) -> (&'a Pat<'a>, usize) {
|
||||
if let PatKind::Ref(pat, _) = pat.kind {
|
||||
peel(pat, count + 1)
|
||||
} else {
|
||||
(pat, count)
|
||||
}
|
||||
}
|
||||
peel(pat, 0)
|
||||
}
|
||||
|
||||
/// Peels off up to the given number of references on the expression. Returns the underlying
|
||||
/// expression and the number of references removed.
|
||||
pub fn peel_n_hir_expr_refs(expr: &'a Expr<'a>, count: usize) -> (&'a Expr<'a>, usize) {
|
||||
fn f(expr: &'a Expr<'a>, count: usize, target: usize) -> (&'a Expr<'a>, usize) {
|
||||
match expr.kind {
|
||||
ExprKind::AddrOf(_, _, expr) if count != target => f(expr, count + 1, target),
|
||||
_ => (expr, count),
|
||||
}
|
||||
}
|
||||
f(expr, 0, count)
|
||||
}
|
||||
|
||||
/// Peels off all references on the type. Returns the underlying type and the number of references
|
||||
/// removed.
|
||||
pub fn peel_mid_ty_refs(ty: Ty<'_>) -> (Ty<'_>, usize) {
|
||||
fn peel(ty: Ty<'_>, count: usize) -> (Ty<'_>, usize) {
|
||||
if let ty::Ref(_, ty, _) = ty.kind() {
|
||||
peel(ty, count + 1)
|
||||
} else {
|
||||
(ty, count)
|
||||
}
|
||||
}
|
||||
peel(ty, 0)
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! unwrap_cargo_metadata {
|
||||
($cx: ident, $lint: ident, $deps: expr) => {{
|
||||
|
@ -2,7 +2,8 @@ use std::borrow::Cow;
|
||||
use std::ops::Range;
|
||||
|
||||
use crate::utils::{snippet_with_applicability, span_lint, span_lint_and_sugg, span_lint_and_then};
|
||||
use rustc_ast::ast::{Expr, ExprKind, Item, ItemKind, MacCall, StrLit, StrStyle};
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::ast::{Expr, ExprKind, Item, ItemKind, LitKind, MacCall, StrLit, StrStyle};
|
||||
use rustc_ast::token;
|
||||
use rustc_ast::tokenstream::TokenStream;
|
||||
use rustc_errors::Applicability;
|
||||
@ -437,7 +438,7 @@ impl Write {
|
||||
return (Some(fmtstr), None);
|
||||
};
|
||||
match &token_expr.kind {
|
||||
ExprKind::Lit(_) => {
|
||||
ExprKind::Lit(lit) if !matches!(lit.kind, LitKind::Int(..) | LitKind::Float(..)) => {
|
||||
let mut all_simple = true;
|
||||
let mut seen = false;
|
||||
for arg in &args {
|
||||
@ -457,8 +458,11 @@ impl Write {
|
||||
idx += 1;
|
||||
},
|
||||
ExprKind::Assign(lhs, rhs, _) => {
|
||||
if let ExprKind::Lit(_) = rhs.kind {
|
||||
if let ExprKind::Path(_, p) = &lhs.kind {
|
||||
if_chain! {
|
||||
if let ExprKind::Lit(ref lit) = rhs.kind;
|
||||
if !matches!(lit.kind, LitKind::Int(..) | LitKind::Float(..));
|
||||
if let ExprKind::Path(_, p) = &lhs.kind;
|
||||
then {
|
||||
let mut all_simple = true;
|
||||
let mut seen = false;
|
||||
for arg in &args {
|
||||
|
@ -6,7 +6,7 @@ use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
use rustc_target::abi::LayoutOf as _;
|
||||
use rustc_typeck::hir_ty_to_ty;
|
||||
|
||||
use crate::utils::{is_type_diagnostic_item, match_type, paths, span_lint_and_help};
|
||||
use crate::utils::{is_normalizable, is_type_diagnostic_item, match_type, paths, span_lint_and_help};
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// **What it does:** Checks for maps with zero-sized value types anywhere in the code.
|
||||
@ -50,6 +50,8 @@ impl LateLintPass<'_> for ZeroSizedMapValues {
|
||||
if is_type_diagnostic_item(cx, ty, sym!(hashmap_type)) || match_type(cx, ty, &paths::BTREEMAP);
|
||||
if let Adt(_, ref substs) = ty.kind();
|
||||
let ty = substs.type_at(1);
|
||||
// Do this to prevent `layout_of` crashing, being unable to fully normalize `ty`.
|
||||
if is_normalizable(cx, cx.param_env, ty);
|
||||
if let Ok(layout) = cx.layout_of(ty);
|
||||
if layout.is_zst();
|
||||
then {
|
||||
|
@ -23,6 +23,7 @@ because that's clearly a non-descriptive name.
|
||||
- [Running rustfmt](#running-rustfmt)
|
||||
- [Debugging](#debugging)
|
||||
- [PR Checklist](#pr-checklist)
|
||||
- [Adding configuration to a lint](#adding-configuration-to-a-lint)
|
||||
- [Cheatsheet](#cheatsheet)
|
||||
|
||||
## Setup
|
||||
@ -526,6 +527,81 @@ Before submitting your PR make sure you followed all of the basic requirements:
|
||||
- \[ ] Added lint documentation
|
||||
- \[ ] Run `cargo dev fmt`
|
||||
|
||||
## Adding configuration to a lint
|
||||
|
||||
Clippy supports the configuration of lints values using a `clippy.toml` file in the workspace
|
||||
directory. Adding a configuration to a lint can be useful for thresholds or to constrain some
|
||||
behavior that can be seen as a false positive for some users. Adding a configuration is done
|
||||
in the following steps:
|
||||
|
||||
1. Adding a new configuration entry to [clippy_lints::utils::conf](/clippy_lints/src/utils/conf.rs)
|
||||
like this:
|
||||
```rust
|
||||
/// Lint: LINT_NAME. <The configuration field doc comment>
|
||||
(configuration_ident, "configuration_value": Type, DefaultValue),
|
||||
```
|
||||
The configuration value and identifier should usually be the same. The doc comment will be
|
||||
automatically added to the lint documentation.
|
||||
2. Adding the configuration value to the lint impl struct:
|
||||
1. This first requires the definition of a lint impl struct. Lint impl structs are usually
|
||||
generated with the `declare_lint_pass!` macro. This struct needs to be defined manually
|
||||
to add some kind of metadata to it:
|
||||
```rust
|
||||
// Generated struct definition
|
||||
declare_lint_pass!(StructName => [
|
||||
LINT_NAME
|
||||
]);
|
||||
|
||||
// New manual definition struct
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct StructName {}
|
||||
|
||||
impl_lint_pass!(StructName => [
|
||||
LINT_NAME
|
||||
]);
|
||||
```
|
||||
|
||||
2. Next add the configuration value and a corresponding creation method like this:
|
||||
```rust
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct StructName {
|
||||
configuration_ident: Type,
|
||||
}
|
||||
|
||||
// ...
|
||||
|
||||
impl StructName {
|
||||
pub fn new(configuration_ident: Type) -> Self {
|
||||
Self {
|
||||
configuration_ident,
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
3. Passing the configuration value to the lint impl struct:
|
||||
|
||||
First find the struct construction in the [clippy_lints lib file](/clippy_lints/src/lib.rs).
|
||||
Make sure that `clippy dev update_lints` added it beforehand. The configuration value is now
|
||||
cloned or copied into a local value that is then passed to the impl struct like this:
|
||||
```rust
|
||||
// Default generated registration:
|
||||
store.register_late_pass(|| box module::StructName);
|
||||
|
||||
// New registration with configuration value
|
||||
let configuration_ident = conf.configuration_ident.clone();
|
||||
store.register_late_pass(move || box module::StructName::new(configuration_ident));
|
||||
```
|
||||
|
||||
Congratulations the work is almost done. The configuration value can now be accessed
|
||||
in the linting code via `self.configuration_ident`.
|
||||
|
||||
4. Adding tests:
|
||||
1. The default configured value can be tested like any normal lint in [`tests/ui`](/tests/ui).
|
||||
2. The configuration itself will be tested separately in [`tests/ui-toml`](/tests/ui-toml).
|
||||
Simply add a new subfolder with a fitting name. This folder contains a `clippy.toml` file
|
||||
with the configuration value and a rust file that should be linted by clippy. The test can
|
||||
otherwise be written as usual.
|
||||
|
||||
## Cheatsheet
|
||||
|
||||
Here are some pointers to things you are likely going to need for every lint:
|
||||
|
@ -11,6 +11,7 @@ the codebase take a look at [Adding Lints] or [Common Tools].
|
||||
- [Get the Code](#get-the-code)
|
||||
- [Building and Testing](#building-and-testing)
|
||||
- [`cargo dev`](#cargo-dev)
|
||||
- [Common Abbreviations](#common-abbreviations)
|
||||
- [PR](#pr)
|
||||
|
||||
## Get the Code
|
||||
@ -94,3 +95,22 @@ cargo dev ra_setup
|
||||
|
||||
We follow a rustc no merge-commit policy.
|
||||
See <https://rustc-dev-guide.rust-lang.org/contributing.html#opening-a-pr>.
|
||||
|
||||
## Common Abbreviations
|
||||
|
||||
| Abbreviation | Meaning |
|
||||
| ------------ | -------------------------------------- |
|
||||
| UB | Undefined Behavior |
|
||||
| FP | False Positive |
|
||||
| FN | False Negative |
|
||||
| ICE | Internal Compiler Error |
|
||||
| AST | Abstract Syntax Tree |
|
||||
| MIR | Mid-Level Intermediate Representation |
|
||||
| HIR | High-Level Intermediate Representation |
|
||||
| TCX | Type context |
|
||||
|
||||
This is a concise list of abbreviations that can come up during clippy development. An extensive
|
||||
general list can be found in the [rustc-dev-guide glossary][glossary]. Always feel free to ask if
|
||||
an abbreviation or meaning is unclear to you.
|
||||
|
||||
[glossary]: https://rustc-dev-guide.rust-lang.org/appendix/glossary.html
|
||||
|
3372
src/tools/clippy/lintcheck-logs/logs.txt
Normal file
3372
src/tools/clippy/lintcheck-logs/logs.txt
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,3 +1,3 @@
|
||||
[toolchain]
|
||||
channel = "nightly-2021-01-15"
|
||||
channel = "nightly-2021-01-30"
|
||||
components = ["llvm-tools-preview", "rustc-dev", "rust-src", "rustfmt"]
|
||||
|
@ -44,7 +44,9 @@ fn third_party_crates() -> String {
|
||||
};
|
||||
if let Some(name) = path.file_name().and_then(OsStr::to_str) {
|
||||
for dep in CRATES {
|
||||
if name.starts_with(&format!("lib{}-", dep)) && name.ends_with(".rlib") {
|
||||
if name.starts_with(&format!("lib{}-", dep))
|
||||
&& name.rsplit('.').next().map(|ext| ext.eq_ignore_ascii_case("rlib")) == Some(true)
|
||||
{
|
||||
if let Some(old) = crates.insert(dep, path.clone()) {
|
||||
panic!("Found multiple rlibs for crate `{}`: `{:?}` and `{:?}", dep, old, path);
|
||||
}
|
||||
|
@ -18,6 +18,9 @@ mod paths {
|
||||
|
||||
// Path with bad module
|
||||
pub const BAD_MOD_PATH: [&str; 2] = ["std", "xxx"];
|
||||
|
||||
// Path to method on an enum inherent impl
|
||||
pub const OPTION_IS_SOME: [&str; 4] = ["core", "option", "Option", "is_some"];
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -0,0 +1,44 @@
|
||||
#![warn(clippy::case_sensitive_file_extension_comparisons)]
|
||||
|
||||
use std::string::String;
|
||||
|
||||
struct TestStruct {}
|
||||
|
||||
impl TestStruct {
|
||||
fn ends_with(self, arg: &str) {}
|
||||
}
|
||||
|
||||
fn is_rust_file(filename: &str) -> bool {
|
||||
filename.ends_with(".rs")
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// std::string::String and &str should trigger the lint failure with .ext12
|
||||
let _ = String::from("").ends_with(".ext12");
|
||||
let _ = "str".ends_with(".ext12");
|
||||
|
||||
// The test struct should not trigger the lint failure with .ext12
|
||||
TestStruct {}.ends_with(".ext12");
|
||||
|
||||
// std::string::String and &str should trigger the lint failure with .EXT12
|
||||
let _ = String::from("").ends_with(".EXT12");
|
||||
let _ = "str".ends_with(".EXT12");
|
||||
|
||||
// The test struct should not trigger the lint failure with .EXT12
|
||||
TestStruct {}.ends_with(".EXT12");
|
||||
|
||||
// Should not trigger the lint failure with .eXT12
|
||||
let _ = String::from("").ends_with(".eXT12");
|
||||
let _ = "str".ends_with(".eXT12");
|
||||
TestStruct {}.ends_with(".eXT12");
|
||||
|
||||
// Should not trigger the lint failure with .EXT123 (too long)
|
||||
let _ = String::from("").ends_with(".EXT123");
|
||||
let _ = "str".ends_with(".EXT123");
|
||||
TestStruct {}.ends_with(".EXT123");
|
||||
|
||||
// Shouldn't fail if it doesn't start with a dot
|
||||
let _ = String::from("").ends_with("a.ext");
|
||||
let _ = "str".ends_with("a.extA");
|
||||
TestStruct {}.ends_with("a.ext");
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
error: case-sensitive file extension comparison
|
||||
--> $DIR/case_sensitive_file_extension_comparisons.rs:12:14
|
||||
|
|
||||
LL | filename.ends_with(".rs")
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `-D clippy::case-sensitive-file-extension-comparisons` implied by `-D warnings`
|
||||
= help: consider using a case-insensitive comparison instead
|
||||
|
||||
error: case-sensitive file extension comparison
|
||||
--> $DIR/case_sensitive_file_extension_comparisons.rs:17:30
|
||||
|
|
||||
LL | let _ = String::from("").ends_with(".ext12");
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: consider using a case-insensitive comparison instead
|
||||
|
||||
error: case-sensitive file extension comparison
|
||||
--> $DIR/case_sensitive_file_extension_comparisons.rs:18:19
|
||||
|
|
||||
LL | let _ = "str".ends_with(".ext12");
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: consider using a case-insensitive comparison instead
|
||||
|
||||
error: case-sensitive file extension comparison
|
||||
--> $DIR/case_sensitive_file_extension_comparisons.rs:24:30
|
||||
|
|
||||
LL | let _ = String::from("").ends_with(".EXT12");
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: consider using a case-insensitive comparison instead
|
||||
|
||||
error: case-sensitive file extension comparison
|
||||
--> $DIR/case_sensitive_file_extension_comparisons.rs:25:19
|
||||
|
|
||||
LL | let _ = "str".ends_with(".EXT12");
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: consider using a case-insensitive comparison instead
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
|
@ -40,6 +40,35 @@ fn lint_cases(opt_opt: Option<Option<u32>>, res_opt: Result<Option<u32>, String>
|
||||
// there is still a better way to write this.
|
||||
mac!(res_opt => Ok(val), val => Some(n), foo(n));
|
||||
}
|
||||
|
||||
// deref reference value
|
||||
match Some(&[1]) {
|
||||
Some(s) => match *s {
|
||||
[n] => foo(n),
|
||||
_ => (),
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
|
||||
// ref pattern and deref
|
||||
match Some(&[1]) {
|
||||
Some(ref s) => match &*s {
|
||||
[n] => foo(n),
|
||||
_ => (),
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
fn no_lint() {
|
||||
// deref inner value (cannot pattern match with Vec)
|
||||
match Some(vec![1]) {
|
||||
Some(s) => match *s {
|
||||
[n] => foo(n),
|
||||
_ => (),
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
fn make<T>() -> T {
|
||||
|
@ -57,5 +57,41 @@ LL | mac!(res_opt => Ok(val), val => Some(n), foo(n));
|
||||
| Replace this binding
|
||||
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
error: Unnecessary nested match
|
||||
--> $DIR/collapsible_match2.rs:46:20
|
||||
|
|
||||
LL | Some(s) => match *s {
|
||||
| ____________________^
|
||||
LL | | [n] => foo(n),
|
||||
LL | | _ => (),
|
||||
LL | | },
|
||||
| |_________^
|
||||
|
|
||||
help: The outer pattern can be modified to include the inner pattern.
|
||||
--> $DIR/collapsible_match2.rs:46:14
|
||||
|
|
||||
LL | Some(s) => match *s {
|
||||
| ^ Replace this binding
|
||||
LL | [n] => foo(n),
|
||||
| ^^^ with this pattern
|
||||
|
||||
error: Unnecessary nested match
|
||||
--> $DIR/collapsible_match2.rs:55:24
|
||||
|
|
||||
LL | Some(ref s) => match &*s {
|
||||
| ________________________^
|
||||
LL | | [n] => foo(n),
|
||||
LL | | _ => (),
|
||||
LL | | },
|
||||
| |_________^
|
||||
|
|
||||
help: The outer pattern can be modified to include the inner pattern.
|
||||
--> $DIR/collapsible_match2.rs:55:14
|
||||
|
|
||||
LL | Some(ref s) => match &*s {
|
||||
| ^^^^^ Replace this binding
|
||||
LL | [n] => foo(n),
|
||||
| ^^^ with this pattern
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
|
||||
|
@ -11,7 +11,7 @@ struct S {
|
||||
f: Vec<Vec<Box<(u32, u32, u32, u32)>>>,
|
||||
}
|
||||
|
||||
struct TS(Vec<Vec<Box<(u32, u32, u32, u32)>>>);
|
||||
struct Ts(Vec<Vec<Box<(u32, u32, u32, u32)>>>);
|
||||
|
||||
enum E {
|
||||
Tuple(Vec<Vec<Box<(u32, u32, u32, u32)>>>),
|
||||
|
@ -21,7 +21,7 @@ LL | f: Vec<Vec<Box<(u32, u32, u32, u32)>>>,
|
||||
error: very complex type used. Consider factoring parts into `type` definitions
|
||||
--> $DIR/complex_types.rs:14:11
|
||||
|
|
||||
LL | struct TS(Vec<Vec<Box<(u32, u32, u32, u32)>>>);
|
||||
LL | struct Ts(Vec<Vec<Box<(u32, u32, u32, u32)>>>);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: very complex type used. Consider factoring parts into `type` definitions
|
||||
|
@ -1,5 +1,6 @@
|
||||
// originally from rustc ./src/test/ui/regions/issue-78262.rs
|
||||
// ICE: to get the signature of a closure, use substs.as_closure().sig() not fn_sig()
|
||||
#![allow(clippy::upper_case_acronyms)]
|
||||
|
||||
trait TT {}
|
||||
|
||||
|
@ -1,13 +1,13 @@
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/ice-6256.rs:11:28
|
||||
--> $DIR/ice-6256.rs:12:28
|
||||
|
|
||||
LL | let f = |x: &dyn TT| x.func(); //[default]~ ERROR: mismatched types
|
||||
| ^^^^ lifetime mismatch
|
||||
|
|
||||
= note: expected reference `&(dyn TT + 'static)`
|
||||
found reference `&dyn TT`
|
||||
note: the anonymous lifetime #1 defined on the body at 11:13...
|
||||
--> $DIR/ice-6256.rs:11:13
|
||||
note: the anonymous lifetime #1 defined on the body at 12:13...
|
||||
--> $DIR/ice-6256.rs:12:13
|
||||
|
|
||||
LL | let f = |x: &dyn TT| x.func(); //[default]~ ERROR: mismatched types
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
16
src/tools/clippy/tests/ui/crashes/ice-6539.rs
Normal file
16
src/tools/clippy/tests/ui/crashes/ice-6539.rs
Normal file
@ -0,0 +1,16 @@
|
||||
// The test for the ICE 6539: https://github.com/rust-lang/rust-clippy/issues/6539.
|
||||
// The cause is that `zero_sized_map_values` used `layout_of` with types from type aliases,
|
||||
// which is essentially the same as the ICE 4968.
|
||||
// Note that only type aliases with associated types caused the crash this time,
|
||||
// not others such as trait impls.
|
||||
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
|
||||
pub trait Trait {
|
||||
type Assoc;
|
||||
}
|
||||
|
||||
type TypeAlias<T> = HashMap<(), <T as Trait>::Assoc>;
|
||||
type TypeAlias2<T> = BTreeMap<(), <T as Trait>::Assoc>;
|
||||
|
||||
fn main() {}
|
@ -10,5 +10,6 @@
|
||||
#[warn(clippy::temporary_cstring_as_ptr)]
|
||||
#[warn(clippy::panic_params)]
|
||||
#[warn(clippy::unknown_clippy_lints)]
|
||||
#[warn(clippy::find_map)]
|
||||
|
||||
fn main() {}
|
||||
|
@ -72,11 +72,17 @@ error: lint `clippy::unknown_clippy_lints` has been removed: this lint has been
|
||||
LL | #[warn(clippy::unknown_clippy_lints)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: lint `clippy::find_map` has been removed: this lint has been replaced by `manual_find_map`, a more specific lint
|
||||
--> $DIR/deprecated.rs:13:8
|
||||
|
|
||||
LL | #[warn(clippy::find_map)]
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
||||
error: lint `clippy::unstable_as_slice` has been removed: `Vec::as_slice` has been stabilized in 1.7
|
||||
--> $DIR/deprecated.rs:1:8
|
||||
|
|
||||
LL | #[warn(clippy::unstable_as_slice)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 13 previous errors
|
||||
error: aborting due to 14 previous errors
|
||||
|
||||
|
@ -53,6 +53,7 @@ fn test_units() {
|
||||
/// DirectX
|
||||
/// ECMAScript
|
||||
/// OAuth GraphQL
|
||||
/// WebGL
|
||||
/// TeX LaTeX BibTeX BibLaTeX
|
||||
/// CamelCase (see also #2395)
|
||||
/// be_sure_we_got_to_the_end_of_it
|
||||
|
@ -55,133 +55,133 @@ LL | /// be_sure_we_got_to_the_end_of_it
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
|
||||
--> $DIR/doc.rs:58:5
|
||||
--> $DIR/doc.rs:59:5
|
||||
|
|
||||
LL | /// be_sure_we_got_to_the_end_of_it
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: you should put `link_with_underscores` between ticks in the documentation
|
||||
--> $DIR/doc.rs:62:22
|
||||
--> $DIR/doc.rs:63:22
|
||||
|
|
||||
LL | /// This test has [a link_with_underscores][chunked-example] inside it. See #823.
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: you should put `inline_link2` between ticks in the documentation
|
||||
--> $DIR/doc.rs:65:21
|
||||
--> $DIR/doc.rs:66:21
|
||||
|
|
||||
LL | /// It can also be [inline_link2].
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
|
||||
--> $DIR/doc.rs:75:5
|
||||
--> $DIR/doc.rs:76:5
|
||||
|
|
||||
LL | /// be_sure_we_got_to_the_end_of_it
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: you should put `CamelCaseThing` between ticks in the documentation
|
||||
--> $DIR/doc.rs:83:8
|
||||
--> $DIR/doc.rs:84:8
|
||||
|
|
||||
LL | /// ## CamelCaseThing
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
||||
error: you should put `CamelCaseThing` between ticks in the documentation
|
||||
--> $DIR/doc.rs:86:7
|
||||
--> $DIR/doc.rs:87:7
|
||||
|
|
||||
LL | /// # CamelCaseThing
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
||||
error: you should put `CamelCaseThing` between ticks in the documentation
|
||||
--> $DIR/doc.rs:88:22
|
||||
--> $DIR/doc.rs:89:22
|
||||
|
|
||||
LL | /// Not a title #897 CamelCaseThing
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
||||
error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
|
||||
--> $DIR/doc.rs:89:5
|
||||
--> $DIR/doc.rs:90:5
|
||||
|
|
||||
LL | /// be_sure_we_got_to_the_end_of_it
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
|
||||
--> $DIR/doc.rs:96:5
|
||||
--> $DIR/doc.rs:97:5
|
||||
|
|
||||
LL | /// be_sure_we_got_to_the_end_of_it
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
|
||||
--> $DIR/doc.rs:109:5
|
||||
--> $DIR/doc.rs:110:5
|
||||
|
|
||||
LL | /// be_sure_we_got_to_the_end_of_it
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: you should put `FooBar` between ticks in the documentation
|
||||
--> $DIR/doc.rs:120:43
|
||||
--> $DIR/doc.rs:121:43
|
||||
|
|
||||
LL | /** E.g., serialization of an empty list: FooBar
|
||||
| ^^^^^^
|
||||
|
||||
error: you should put `BarQuz` between ticks in the documentation
|
||||
--> $DIR/doc.rs:125:5
|
||||
--> $DIR/doc.rs:126:5
|
||||
|
|
||||
LL | And BarQuz too.
|
||||
| ^^^^^^
|
||||
|
||||
error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
|
||||
--> $DIR/doc.rs:126:1
|
||||
--> $DIR/doc.rs:127:1
|
||||
|
|
||||
LL | be_sure_we_got_to_the_end_of_it
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: you should put `FooBar` between ticks in the documentation
|
||||
--> $DIR/doc.rs:131:43
|
||||
--> $DIR/doc.rs:132:43
|
||||
|
|
||||
LL | /** E.g., serialization of an empty list: FooBar
|
||||
| ^^^^^^
|
||||
|
||||
error: you should put `BarQuz` between ticks in the documentation
|
||||
--> $DIR/doc.rs:136:5
|
||||
--> $DIR/doc.rs:137:5
|
||||
|
|
||||
LL | And BarQuz too.
|
||||
| ^^^^^^
|
||||
|
||||
error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
|
||||
--> $DIR/doc.rs:137:1
|
||||
--> $DIR/doc.rs:138:1
|
||||
|
|
||||
LL | be_sure_we_got_to_the_end_of_it
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
|
||||
--> $DIR/doc.rs:148:5
|
||||
--> $DIR/doc.rs:149:5
|
||||
|
|
||||
LL | /// be_sure_we_got_to_the_end_of_it
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: you should put bare URLs between `<`/`>` or make a proper Markdown link
|
||||
--> $DIR/doc.rs:175:13
|
||||
--> $DIR/doc.rs:176:13
|
||||
|
|
||||
LL | /// Not ok: http://www.unicode.org
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: you should put bare URLs between `<`/`>` or make a proper Markdown link
|
||||
--> $DIR/doc.rs:176:13
|
||||
--> $DIR/doc.rs:177:13
|
||||
|
|
||||
LL | /// Not ok: https://www.unicode.org
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: you should put bare URLs between `<`/`>` or make a proper Markdown link
|
||||
--> $DIR/doc.rs:177:13
|
||||
--> $DIR/doc.rs:178:13
|
||||
|
|
||||
LL | /// Not ok: http://www.unicode.org/
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: you should put bare URLs between `<`/`>` or make a proper Markdown link
|
||||
--> $DIR/doc.rs:178:13
|
||||
--> $DIR/doc.rs:179:13
|
||||
|
|
||||
LL | /// Not ok: http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: you should put `mycrate::Collection` between ticks in the documentation
|
||||
--> $DIR/doc.rs:181:22
|
||||
--> $DIR/doc.rs:182:22
|
||||
|
|
||||
LL | /// An iterator over mycrate::Collection's values.
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -1,6 +1,6 @@
|
||||
#![feature(non_ascii_idents)]
|
||||
#![warn(clippy::enum_variant_names, clippy::pub_enum_variant_names)]
|
||||
#![allow(non_camel_case_types)]
|
||||
#![allow(non_camel_case_types, clippy::upper_case_acronyms)]
|
||||
|
||||
enum FakeCallType {
|
||||
CALL,
|
||||
|
82
src/tools/clippy/tests/ui/exhaustive_items.fixed
Normal file
82
src/tools/clippy/tests/ui/exhaustive_items.fixed
Normal file
@ -0,0 +1,82 @@
|
||||
// run-rustfix
|
||||
|
||||
#![deny(clippy::exhaustive_enums, clippy::exhaustive_structs)]
|
||||
#![allow(unused)]
|
||||
|
||||
fn main() {
|
||||
// nop
|
||||
}
|
||||
|
||||
pub mod enums {
|
||||
#[non_exhaustive]
|
||||
pub enum Exhaustive {
|
||||
Foo,
|
||||
Bar,
|
||||
Baz,
|
||||
Quux(String),
|
||||
}
|
||||
|
||||
/// Some docs
|
||||
#[repr(C)]
|
||||
#[non_exhaustive]
|
||||
pub enum ExhaustiveWithAttrs {
|
||||
Foo,
|
||||
Bar,
|
||||
Baz,
|
||||
Quux(String),
|
||||
}
|
||||
|
||||
// no warning, already non_exhaustive
|
||||
#[non_exhaustive]
|
||||
pub enum NonExhaustive {
|
||||
Foo,
|
||||
Bar,
|
||||
Baz,
|
||||
Quux(String),
|
||||
}
|
||||
|
||||
// no warning, private
|
||||
enum ExhaustivePrivate {
|
||||
Foo,
|
||||
Bar,
|
||||
Baz,
|
||||
Quux(String),
|
||||
}
|
||||
|
||||
// no warning, private
|
||||
#[non_exhaustive]
|
||||
enum NonExhaustivePrivate {
|
||||
Foo,
|
||||
Bar,
|
||||
Baz,
|
||||
Quux(String),
|
||||
}
|
||||
}
|
||||
|
||||
pub mod structs {
|
||||
#[non_exhaustive]
|
||||
pub struct Exhaustive {
|
||||
foo: u8,
|
||||
bar: String,
|
||||
}
|
||||
|
||||
// no warning, already non_exhaustive
|
||||
#[non_exhaustive]
|
||||
pub struct NonExhaustive {
|
||||
foo: u8,
|
||||
bar: String,
|
||||
}
|
||||
|
||||
// no warning, private
|
||||
struct ExhaustivePrivate {
|
||||
foo: u8,
|
||||
bar: String,
|
||||
}
|
||||
|
||||
// no warning, private
|
||||
#[non_exhaustive]
|
||||
struct NonExhaustivePrivate {
|
||||
foo: u8,
|
||||
bar: String,
|
||||
}
|
||||
}
|
79
src/tools/clippy/tests/ui/exhaustive_items.rs
Normal file
79
src/tools/clippy/tests/ui/exhaustive_items.rs
Normal file
@ -0,0 +1,79 @@
|
||||
// run-rustfix
|
||||
|
||||
#![deny(clippy::exhaustive_enums, clippy::exhaustive_structs)]
|
||||
#![allow(unused)]
|
||||
|
||||
fn main() {
|
||||
// nop
|
||||
}
|
||||
|
||||
pub mod enums {
|
||||
pub enum Exhaustive {
|
||||
Foo,
|
||||
Bar,
|
||||
Baz,
|
||||
Quux(String),
|
||||
}
|
||||
|
||||
/// Some docs
|
||||
#[repr(C)]
|
||||
pub enum ExhaustiveWithAttrs {
|
||||
Foo,
|
||||
Bar,
|
||||
Baz,
|
||||
Quux(String),
|
||||
}
|
||||
|
||||
// no warning, already non_exhaustive
|
||||
#[non_exhaustive]
|
||||
pub enum NonExhaustive {
|
||||
Foo,
|
||||
Bar,
|
||||
Baz,
|
||||
Quux(String),
|
||||
}
|
||||
|
||||
// no warning, private
|
||||
enum ExhaustivePrivate {
|
||||
Foo,
|
||||
Bar,
|
||||
Baz,
|
||||
Quux(String),
|
||||
}
|
||||
|
||||
// no warning, private
|
||||
#[non_exhaustive]
|
||||
enum NonExhaustivePrivate {
|
||||
Foo,
|
||||
Bar,
|
||||
Baz,
|
||||
Quux(String),
|
||||
}
|
||||
}
|
||||
|
||||
pub mod structs {
|
||||
pub struct Exhaustive {
|
||||
foo: u8,
|
||||
bar: String,
|
||||
}
|
||||
|
||||
// no warning, already non_exhaustive
|
||||
#[non_exhaustive]
|
||||
pub struct NonExhaustive {
|
||||
foo: u8,
|
||||
bar: String,
|
||||
}
|
||||
|
||||
// no warning, private
|
||||
struct ExhaustivePrivate {
|
||||
foo: u8,
|
||||
bar: String,
|
||||
}
|
||||
|
||||
// no warning, private
|
||||
#[non_exhaustive]
|
||||
struct NonExhaustivePrivate {
|
||||
foo: u8,
|
||||
bar: String,
|
||||
}
|
||||
}
|
61
src/tools/clippy/tests/ui/exhaustive_items.stderr
Normal file
61
src/tools/clippy/tests/ui/exhaustive_items.stderr
Normal file
@ -0,0 +1,61 @@
|
||||
error: exported enums should not be exhaustive
|
||||
--> $DIR/exhaustive_items.rs:11:5
|
||||
|
|
||||
LL | / pub enum Exhaustive {
|
||||
LL | | Foo,
|
||||
LL | | Bar,
|
||||
LL | | Baz,
|
||||
LL | | Quux(String),
|
||||
LL | | }
|
||||
| |_____^
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/exhaustive_items.rs:3:9
|
||||
|
|
||||
LL | #![deny(clippy::exhaustive_enums, clippy::exhaustive_structs)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
help: try adding #[non_exhaustive]
|
||||
|
|
||||
LL | #[non_exhaustive]
|
||||
LL | pub enum Exhaustive {
|
||||
|
|
||||
|
||||
error: exported enums should not be exhaustive
|
||||
--> $DIR/exhaustive_items.rs:20:5
|
||||
|
|
||||
LL | / pub enum ExhaustiveWithAttrs {
|
||||
LL | | Foo,
|
||||
LL | | Bar,
|
||||
LL | | Baz,
|
||||
LL | | Quux(String),
|
||||
LL | | }
|
||||
| |_____^
|
||||
|
|
||||
help: try adding #[non_exhaustive]
|
||||
|
|
||||
LL | #[non_exhaustive]
|
||||
LL | pub enum ExhaustiveWithAttrs {
|
||||
|
|
||||
|
||||
error: exported structs should not be exhaustive
|
||||
--> $DIR/exhaustive_items.rs:55:5
|
||||
|
|
||||
LL | / pub struct Exhaustive {
|
||||
LL | | foo: u8,
|
||||
LL | | bar: String,
|
||||
LL | | }
|
||||
| |_____^
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/exhaustive_items.rs:3:35
|
||||
|
|
||||
LL | #![deny(clippy::exhaustive_enums, clippy::exhaustive_structs)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
help: try adding #[non_exhaustive]
|
||||
|
|
||||
LL | #[non_exhaustive]
|
||||
LL | pub struct Exhaustive {
|
||||
|
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
@ -1,12 +1,3 @@
|
||||
error: called `filter(..).map(..)` on an `Iterator`
|
||||
--> $DIR/filter_methods.rs:6:21
|
||||
|
|
||||
LL | let _: Vec<_> = vec![5; 6].into_iter().filter(|&x| x == 0).map(|x| x * 2).collect();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `-D clippy::filter-map` implied by `-D warnings`
|
||||
= help: this is more succinctly expressed by calling `.filter_map(..)` instead
|
||||
|
||||
error: called `filter(..).flat_map(..)` on an `Iterator`
|
||||
--> $DIR/filter_methods.rs:8:21
|
||||
|
|
||||
@ -17,6 +8,7 @@ LL | | .filter(|&x| x == 0)
|
||||
LL | | .flat_map(|x| x.checked_mul(2))
|
||||
| |_______________________________________^
|
||||
|
|
||||
= note: `-D clippy::filter-map` implied by `-D warnings`
|
||||
= help: this is more succinctly expressed by calling `.flat_map(..)` and filtering by returning `iter::empty()`
|
||||
|
||||
error: called `filter_map(..).flat_map(..)` on an `Iterator`
|
||||
@ -43,5 +35,5 @@ LL | | .map(|x| x.checked_mul(2))
|
||||
|
|
||||
= help: this is more succinctly expressed by only calling `.filter_map(..)` instead
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
|
@ -1,26 +0,0 @@
|
||||
error: called `find(..).map(..)` on an `Iterator`
|
||||
--> $DIR/find_map.rs:20:26
|
||||
|
|
||||
LL | let _: Option<i32> = a.iter().find(|s| s.parse::<i32>().is_ok()).map(|s| s.parse().unwrap());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `-D clippy::find-map` implied by `-D warnings`
|
||||
= help: this is more succinctly expressed by calling `.find_map(..)` instead
|
||||
|
||||
error: called `find(..).map(..)` on an `Iterator`
|
||||
--> $DIR/find_map.rs:23:29
|
||||
|
|
||||
LL | let _: Option<Flavor> = desserts_of_the_week
|
||||
| _____________________________^
|
||||
LL | | .iter()
|
||||
LL | | .find(|dessert| match *dessert {
|
||||
LL | | Dessert::Cake(_) => true,
|
||||
... |
|
||||
LL | | _ => unreachable!(),
|
||||
LL | | });
|
||||
| |__________^
|
||||
|
|
||||
= help: this is more succinctly expressed by calling `.find_map(..)` instead
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
22
src/tools/clippy/tests/ui/inspect_for_each.rs
Normal file
22
src/tools/clippy/tests/ui/inspect_for_each.rs
Normal file
@ -0,0 +1,22 @@
|
||||
#![warn(clippy::inspect_for_each)]
|
||||
|
||||
fn main() {
|
||||
let a: Vec<usize> = vec![1, 2, 3, 4, 5];
|
||||
|
||||
let mut b: Vec<usize> = Vec::new();
|
||||
a.into_iter().inspect(|x| assert!(*x > 0)).for_each(|x| {
|
||||
let y = do_some(x);
|
||||
let z = do_more(y);
|
||||
b.push(z);
|
||||
});
|
||||
|
||||
assert_eq!(b, vec![4, 5, 6, 7, 8]);
|
||||
}
|
||||
|
||||
fn do_some(a: usize) -> usize {
|
||||
a + 1
|
||||
}
|
||||
|
||||
fn do_more(a: usize) -> usize {
|
||||
a + 2
|
||||
}
|
16
src/tools/clippy/tests/ui/inspect_for_each.stderr
Normal file
16
src/tools/clippy/tests/ui/inspect_for_each.stderr
Normal file
@ -0,0 +1,16 @@
|
||||
error: called `inspect(..).for_each(..)` on an `Iterator`
|
||||
--> $DIR/inspect_for_each.rs:7:19
|
||||
|
|
||||
LL | a.into_iter().inspect(|x| assert!(*x > 0)).for_each(|x| {
|
||||
| ___________________^
|
||||
LL | | let y = do_some(x);
|
||||
LL | | let z = do_more(y);
|
||||
LL | | b.push(z);
|
||||
LL | | });
|
||||
| |______^
|
||||
|
|
||||
= note: `-D clippy::inspect-for-each` implied by `-D warnings`
|
||||
= help: move the code from `inspect(..)` to `for_each(..)` and remove the `inspect(..)`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
37
src/tools/clippy/tests/ui/manual_filter_map.fixed
Normal file
37
src/tools/clippy/tests/ui/manual_filter_map.fixed
Normal file
@ -0,0 +1,37 @@
|
||||
// run-rustfix
|
||||
#![allow(dead_code)]
|
||||
#![warn(clippy::manual_filter_map)]
|
||||
#![allow(clippy::redundant_closure)] // FIXME suggestion may have redundant closure
|
||||
|
||||
fn main() {
|
||||
// is_some(), unwrap()
|
||||
let _ = (0..).filter_map(|a| to_opt(a));
|
||||
|
||||
// ref pattern, expect()
|
||||
let _ = (0..).filter_map(|a| to_opt(a));
|
||||
|
||||
// is_ok(), unwrap_or()
|
||||
let _ = (0..).filter_map(|a| to_res(a).ok());
|
||||
}
|
||||
|
||||
fn no_lint() {
|
||||
// no shared code
|
||||
let _ = (0..).filter(|n| *n > 1).map(|n| n + 1);
|
||||
|
||||
// very close but different since filter() provides a reference
|
||||
let _ = (0..).filter(|n| to_opt(n).is_some()).map(|a| to_opt(a).unwrap());
|
||||
|
||||
// similar but different
|
||||
let _ = (0..).filter(|n| to_opt(n).is_some()).map(|n| to_res(n).unwrap());
|
||||
let _ = (0..)
|
||||
.filter(|n| to_opt(n).map(|n| n + 1).is_some())
|
||||
.map(|a| to_opt(a).unwrap());
|
||||
}
|
||||
|
||||
fn to_opt<T>(_: T) -> Option<T> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn to_res<T>(_: T) -> Result<T, ()> {
|
||||
unimplemented!()
|
||||
}
|
37
src/tools/clippy/tests/ui/manual_filter_map.rs
Normal file
37
src/tools/clippy/tests/ui/manual_filter_map.rs
Normal file
@ -0,0 +1,37 @@
|
||||
// run-rustfix
|
||||
#![allow(dead_code)]
|
||||
#![warn(clippy::manual_filter_map)]
|
||||
#![allow(clippy::redundant_closure)] // FIXME suggestion may have redundant closure
|
||||
|
||||
fn main() {
|
||||
// is_some(), unwrap()
|
||||
let _ = (0..).filter(|n| to_opt(*n).is_some()).map(|a| to_opt(a).unwrap());
|
||||
|
||||
// ref pattern, expect()
|
||||
let _ = (0..).filter(|&n| to_opt(n).is_some()).map(|a| to_opt(a).expect("hi"));
|
||||
|
||||
// is_ok(), unwrap_or()
|
||||
let _ = (0..).filter(|&n| to_res(n).is_ok()).map(|a| to_res(a).unwrap_or(1));
|
||||
}
|
||||
|
||||
fn no_lint() {
|
||||
// no shared code
|
||||
let _ = (0..).filter(|n| *n > 1).map(|n| n + 1);
|
||||
|
||||
// very close but different since filter() provides a reference
|
||||
let _ = (0..).filter(|n| to_opt(n).is_some()).map(|a| to_opt(a).unwrap());
|
||||
|
||||
// similar but different
|
||||
let _ = (0..).filter(|n| to_opt(n).is_some()).map(|n| to_res(n).unwrap());
|
||||
let _ = (0..)
|
||||
.filter(|n| to_opt(n).map(|n| n + 1).is_some())
|
||||
.map(|a| to_opt(a).unwrap());
|
||||
}
|
||||
|
||||
fn to_opt<T>(_: T) -> Option<T> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn to_res<T>(_: T) -> Result<T, ()> {
|
||||
unimplemented!()
|
||||
}
|
22
src/tools/clippy/tests/ui/manual_filter_map.stderr
Normal file
22
src/tools/clippy/tests/ui/manual_filter_map.stderr
Normal file
@ -0,0 +1,22 @@
|
||||
error: `filter(..).map(..)` can be simplified as `filter_map(..)`
|
||||
--> $DIR/manual_filter_map.rs:8:19
|
||||
|
|
||||
LL | let _ = (0..).filter(|n| to_opt(*n).is_some()).map(|a| to_opt(a).unwrap());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `filter_map(|a| to_opt(a))`
|
||||
|
|
||||
= note: `-D clippy::manual-filter-map` implied by `-D warnings`
|
||||
|
||||
error: `filter(..).map(..)` can be simplified as `filter_map(..)`
|
||||
--> $DIR/manual_filter_map.rs:11:19
|
||||
|
|
||||
LL | let _ = (0..).filter(|&n| to_opt(n).is_some()).map(|a| to_opt(a).expect("hi"));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `filter_map(|a| to_opt(a))`
|
||||
|
||||
error: `filter(..).map(..)` can be simplified as `filter_map(..)`
|
||||
--> $DIR/manual_filter_map.rs:14:19
|
||||
|
|
||||
LL | let _ = (0..).filter(|&n| to_res(n).is_ok()).map(|a| to_res(a).unwrap_or(1));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `filter_map(|a| to_res(a).ok())`
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
37
src/tools/clippy/tests/ui/manual_find_map.fixed
Normal file
37
src/tools/clippy/tests/ui/manual_find_map.fixed
Normal file
@ -0,0 +1,37 @@
|
||||
// run-rustfix
|
||||
#![allow(dead_code)]
|
||||
#![warn(clippy::manual_find_map)]
|
||||
#![allow(clippy::redundant_closure)] // FIXME suggestion may have redundant closure
|
||||
|
||||
fn main() {
|
||||
// is_some(), unwrap()
|
||||
let _ = (0..).find_map(|a| to_opt(a));
|
||||
|
||||
// ref pattern, expect()
|
||||
let _ = (0..).find_map(|a| to_opt(a));
|
||||
|
||||
// is_ok(), unwrap_or()
|
||||
let _ = (0..).find_map(|a| to_res(a).ok());
|
||||
}
|
||||
|
||||
fn no_lint() {
|
||||
// no shared code
|
||||
let _ = (0..).filter(|n| *n > 1).map(|n| n + 1);
|
||||
|
||||
// very close but different since filter() provides a reference
|
||||
let _ = (0..).find(|n| to_opt(n).is_some()).map(|a| to_opt(a).unwrap());
|
||||
|
||||
// similar but different
|
||||
let _ = (0..).find(|n| to_opt(n).is_some()).map(|n| to_res(n).unwrap());
|
||||
let _ = (0..)
|
||||
.find(|n| to_opt(n).map(|n| n + 1).is_some())
|
||||
.map(|a| to_opt(a).unwrap());
|
||||
}
|
||||
|
||||
fn to_opt<T>(_: T) -> Option<T> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn to_res<T>(_: T) -> Result<T, ()> {
|
||||
unimplemented!()
|
||||
}
|
37
src/tools/clippy/tests/ui/manual_find_map.rs
Normal file
37
src/tools/clippy/tests/ui/manual_find_map.rs
Normal file
@ -0,0 +1,37 @@
|
||||
// run-rustfix
|
||||
#![allow(dead_code)]
|
||||
#![warn(clippy::manual_find_map)]
|
||||
#![allow(clippy::redundant_closure)] // FIXME suggestion may have redundant closure
|
||||
|
||||
fn main() {
|
||||
// is_some(), unwrap()
|
||||
let _ = (0..).find(|n| to_opt(*n).is_some()).map(|a| to_opt(a).unwrap());
|
||||
|
||||
// ref pattern, expect()
|
||||
let _ = (0..).find(|&n| to_opt(n).is_some()).map(|a| to_opt(a).expect("hi"));
|
||||
|
||||
// is_ok(), unwrap_or()
|
||||
let _ = (0..).find(|&n| to_res(n).is_ok()).map(|a| to_res(a).unwrap_or(1));
|
||||
}
|
||||
|
||||
fn no_lint() {
|
||||
// no shared code
|
||||
let _ = (0..).filter(|n| *n > 1).map(|n| n + 1);
|
||||
|
||||
// very close but different since filter() provides a reference
|
||||
let _ = (0..).find(|n| to_opt(n).is_some()).map(|a| to_opt(a).unwrap());
|
||||
|
||||
// similar but different
|
||||
let _ = (0..).find(|n| to_opt(n).is_some()).map(|n| to_res(n).unwrap());
|
||||
let _ = (0..)
|
||||
.find(|n| to_opt(n).map(|n| n + 1).is_some())
|
||||
.map(|a| to_opt(a).unwrap());
|
||||
}
|
||||
|
||||
fn to_opt<T>(_: T) -> Option<T> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn to_res<T>(_: T) -> Result<T, ()> {
|
||||
unimplemented!()
|
||||
}
|
22
src/tools/clippy/tests/ui/manual_find_map.stderr
Normal file
22
src/tools/clippy/tests/ui/manual_find_map.stderr
Normal file
@ -0,0 +1,22 @@
|
||||
error: `find(..).map(..)` can be simplified as `find_map(..)`
|
||||
--> $DIR/manual_find_map.rs:8:19
|
||||
|
|
||||
LL | let _ = (0..).find(|n| to_opt(*n).is_some()).map(|a| to_opt(a).unwrap());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|a| to_opt(a))`
|
||||
|
|
||||
= note: `-D clippy::manual-find-map` implied by `-D warnings`
|
||||
|
||||
error: `find(..).map(..)` can be simplified as `find_map(..)`
|
||||
--> $DIR/manual_find_map.rs:11:19
|
||||
|
|
||||
LL | let _ = (0..).find(|&n| to_opt(n).is_some()).map(|a| to_opt(a).expect("hi"));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|a| to_opt(a))`
|
||||
|
||||
error: `find(..).map(..)` can be simplified as `find_map(..)`
|
||||
--> $DIR/manual_find_map.rs:14:19
|
||||
|
|
||||
LL | let _ = (0..).find(|&n| to_res(n).is_ok()).map(|a| to_res(a).unwrap_or(1));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|a| to_res(a).ok())`
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
@ -99,4 +99,51 @@ fn main() {
|
||||
_ => false,
|
||||
};
|
||||
}
|
||||
|
||||
{
|
||||
// should print "z" in suggestion (#6503)
|
||||
let z = &Some(3);
|
||||
let _z = matches!(z, Some(3));
|
||||
}
|
||||
|
||||
{
|
||||
// this could also print "z" in suggestion..?
|
||||
let z = Some(3);
|
||||
let _z = matches!(&z, Some(3));
|
||||
}
|
||||
|
||||
{
|
||||
enum AnEnum {
|
||||
X,
|
||||
Y,
|
||||
}
|
||||
|
||||
fn foo(_x: AnEnum) {}
|
||||
|
||||
fn main() {
|
||||
let z = AnEnum::X;
|
||||
// we can't remove the reference here!
|
||||
let _ = matches!(&z, AnEnum::X);
|
||||
foo(z);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
struct S(i32);
|
||||
|
||||
fn fun(_val: Option<S>) {}
|
||||
let val = Some(S(42));
|
||||
// we need the reference here because later val is consumed by fun()
|
||||
let _res = matches!(&val, &Some(ref _a));
|
||||
fun(val);
|
||||
}
|
||||
|
||||
{
|
||||
struct S(i32);
|
||||
|
||||
fn fun(_val: Option<S>) {}
|
||||
let val = Some(S(42));
|
||||
let _res = matches!(&val, &Some(ref _a));
|
||||
fun(val);
|
||||
}
|
||||
}
|
||||
|
@ -119,4 +119,66 @@ fn main() {
|
||||
_ => false,
|
||||
};
|
||||
}
|
||||
|
||||
{
|
||||
// should print "z" in suggestion (#6503)
|
||||
let z = &Some(3);
|
||||
let _z = match &z {
|
||||
Some(3) => true,
|
||||
_ => false,
|
||||
};
|
||||
}
|
||||
|
||||
{
|
||||
// this could also print "z" in suggestion..?
|
||||
let z = Some(3);
|
||||
let _z = match &z {
|
||||
Some(3) => true,
|
||||
_ => false,
|
||||
};
|
||||
}
|
||||
|
||||
{
|
||||
enum AnEnum {
|
||||
X,
|
||||
Y,
|
||||
}
|
||||
|
||||
fn foo(_x: AnEnum) {}
|
||||
|
||||
fn main() {
|
||||
let z = AnEnum::X;
|
||||
// we can't remove the reference here!
|
||||
let _ = match &z {
|
||||
AnEnum::X => true,
|
||||
_ => false,
|
||||
};
|
||||
foo(z);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
struct S(i32);
|
||||
|
||||
fn fun(_val: Option<S>) {}
|
||||
let val = Some(S(42));
|
||||
// we need the reference here because later val is consumed by fun()
|
||||
let _res = match &val {
|
||||
&Some(ref _a) => true,
|
||||
_ => false,
|
||||
};
|
||||
fun(val);
|
||||
}
|
||||
|
||||
{
|
||||
struct S(i32);
|
||||
|
||||
fn fun(_val: Option<S>) {}
|
||||
let val = Some(S(42));
|
||||
let _res = match &val {
|
||||
&Some(ref _a) => true,
|
||||
_ => false,
|
||||
};
|
||||
fun(val);
|
||||
}
|
||||
}
|
||||
|
@ -70,5 +70,88 @@ LL | | _ => true,
|
||||
LL | | };
|
||||
| |_________^ help: try this: `!matches!(x, E::B(_) | E::C)`
|
||||
|
||||
error: aborting due to 7 previous errors
|
||||
error: match expression looks like `matches!` macro
|
||||
--> $DIR/match_expr_like_matches_macro.rs:126:18
|
||||
|
|
||||
LL | let _z = match &z {
|
||||
| __________________^
|
||||
LL | | Some(3) => true,
|
||||
LL | | _ => false,
|
||||
LL | | };
|
||||
| |_________^ help: try this: `matches!(z, Some(3))`
|
||||
|
||||
error: match expression looks like `matches!` macro
|
||||
--> $DIR/match_expr_like_matches_macro.rs:135:18
|
||||
|
|
||||
LL | let _z = match &z {
|
||||
| __________________^
|
||||
LL | | Some(3) => true,
|
||||
LL | | _ => false,
|
||||
LL | | };
|
||||
| |_________^ help: try this: `matches!(&z, Some(3))`
|
||||
|
||||
error: match expression looks like `matches!` macro
|
||||
--> $DIR/match_expr_like_matches_macro.rs:152:21
|
||||
|
|
||||
LL | let _ = match &z {
|
||||
| _____________________^
|
||||
LL | | AnEnum::X => true,
|
||||
LL | | _ => false,
|
||||
LL | | };
|
||||
| |_____________^ help: try this: `matches!(&z, AnEnum::X)`
|
||||
|
||||
error: match expression looks like `matches!` macro
|
||||
--> $DIR/match_expr_like_matches_macro.rs:166:20
|
||||
|
|
||||
LL | let _res = match &val {
|
||||
| ____________________^
|
||||
LL | | &Some(ref _a) => true,
|
||||
LL | | _ => false,
|
||||
LL | | };
|
||||
| |_________^ help: try this: `matches!(&val, &Some(ref _a))`
|
||||
|
||||
error: you don't need to add `&` to both the expression and the patterns
|
||||
--> $DIR/match_expr_like_matches_macro.rs:166:20
|
||||
|
|
||||
LL | let _res = match &val {
|
||||
| ____________________^
|
||||
LL | | &Some(ref _a) => true,
|
||||
LL | | _ => false,
|
||||
LL | | };
|
||||
| |_________^
|
||||
|
|
||||
= note: `-D clippy::match-ref-pats` implied by `-D warnings`
|
||||
help: try
|
||||
|
|
||||
LL | let _res = match val {
|
||||
LL | Some(ref _a) => true,
|
||||
|
|
||||
|
||||
error: match expression looks like `matches!` macro
|
||||
--> $DIR/match_expr_like_matches_macro.rs:178:20
|
||||
|
|
||||
LL | let _res = match &val {
|
||||
| ____________________^
|
||||
LL | | &Some(ref _a) => true,
|
||||
LL | | _ => false,
|
||||
LL | | };
|
||||
| |_________^ help: try this: `matches!(&val, &Some(ref _a))`
|
||||
|
||||
error: you don't need to add `&` to both the expression and the patterns
|
||||
--> $DIR/match_expr_like_matches_macro.rs:178:20
|
||||
|
|
||||
LL | let _res = match &val {
|
||||
| ____________________^
|
||||
LL | | &Some(ref _a) => true,
|
||||
LL | | _ => false,
|
||||
LL | | };
|
||||
| |_________^
|
||||
|
|
||||
help: try
|
||||
|
|
||||
LL | let _res = match val {
|
||||
LL | Some(ref _a) => true,
|
||||
|
|
||||
|
||||
error: aborting due to 14 previous errors
|
||||
|
||||
|
@ -1,7 +1,13 @@
|
||||
// run-rustfix
|
||||
|
||||
#![warn(clippy::needless_question_mark)]
|
||||
#![allow(clippy::needless_return, clippy::unnecessary_unwrap, dead_code, unused_must_use)]
|
||||
#![allow(
|
||||
clippy::needless_return,
|
||||
clippy::unnecessary_unwrap,
|
||||
clippy::upper_case_acronyms,
|
||||
dead_code,
|
||||
unused_must_use
|
||||
)]
|
||||
#![feature(custom_inner_attributes)]
|
||||
|
||||
struct TO {
|
||||
|
@ -1,7 +1,13 @@
|
||||
// run-rustfix
|
||||
|
||||
#![warn(clippy::needless_question_mark)]
|
||||
#![allow(clippy::needless_return, clippy::unnecessary_unwrap, dead_code, unused_must_use)]
|
||||
#![allow(
|
||||
clippy::needless_return,
|
||||
clippy::unnecessary_unwrap,
|
||||
clippy::upper_case_acronyms,
|
||||
dead_code,
|
||||
unused_must_use
|
||||
)]
|
||||
#![feature(custom_inner_attributes)]
|
||||
|
||||
struct TO {
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: Question mark operator is useless here
|
||||
--> $DIR/needless_question_mark.rs:17:12
|
||||
--> $DIR/needless_question_mark.rs:23:12
|
||||
|
|
||||
LL | return Some(to.magic?);
|
||||
| ^^^^^^^^^^^^^^^ help: try: `to.magic`
|
||||
@ -7,79 +7,79 @@ LL | return Some(to.magic?);
|
||||
= note: `-D clippy::needless-question-mark` implied by `-D warnings`
|
||||
|
||||
error: Question mark operator is useless here
|
||||
--> $DIR/needless_question_mark.rs:25:12
|
||||
--> $DIR/needless_question_mark.rs:31:12
|
||||
|
|
||||
LL | return Some(to.magic?)
|
||||
| ^^^^^^^^^^^^^^^ help: try: `to.magic`
|
||||
|
||||
error: Question mark operator is useless here
|
||||
--> $DIR/needless_question_mark.rs:30:5
|
||||
--> $DIR/needless_question_mark.rs:36:5
|
||||
|
|
||||
LL | Some(to.magic?)
|
||||
| ^^^^^^^^^^^^^^^ help: try: `to.magic`
|
||||
|
||||
error: Question mark operator is useless here
|
||||
--> $DIR/needless_question_mark.rs:35:21
|
||||
--> $DIR/needless_question_mark.rs:41:21
|
||||
|
|
||||
LL | to.and_then(|t| Some(t.magic?))
|
||||
| ^^^^^^^^^^^^^^ help: try: `t.magic`
|
||||
|
||||
error: Question mark operator is useless here
|
||||
--> $DIR/needless_question_mark.rs:44:9
|
||||
--> $DIR/needless_question_mark.rs:50:9
|
||||
|
|
||||
LL | Some(t.magic?)
|
||||
| ^^^^^^^^^^^^^^ help: try: `t.magic`
|
||||
|
||||
error: Question mark operator is useless here
|
||||
--> $DIR/needless_question_mark.rs:49:12
|
||||
--> $DIR/needless_question_mark.rs:55:12
|
||||
|
|
||||
LL | return Ok(tr.magic?);
|
||||
| ^^^^^^^^^^^^^ help: try: `tr.magic`
|
||||
|
||||
error: Question mark operator is useless here
|
||||
--> $DIR/needless_question_mark.rs:56:12
|
||||
--> $DIR/needless_question_mark.rs:62:12
|
||||
|
|
||||
LL | return Ok(tr.magic?)
|
||||
| ^^^^^^^^^^^^^ help: try: `tr.magic`
|
||||
|
||||
error: Question mark operator is useless here
|
||||
--> $DIR/needless_question_mark.rs:60:5
|
||||
--> $DIR/needless_question_mark.rs:66:5
|
||||
|
|
||||
LL | Ok(tr.magic?)
|
||||
| ^^^^^^^^^^^^^ help: try: `tr.magic`
|
||||
|
||||
error: Question mark operator is useless here
|
||||
--> $DIR/needless_question_mark.rs:64:21
|
||||
--> $DIR/needless_question_mark.rs:70:21
|
||||
|
|
||||
LL | tr.and_then(|t| Ok(t.magic?))
|
||||
| ^^^^^^^^^^^^ help: try: `t.magic`
|
||||
|
||||
error: Question mark operator is useless here
|
||||
--> $DIR/needless_question_mark.rs:72:9
|
||||
--> $DIR/needless_question_mark.rs:78:9
|
||||
|
|
||||
LL | Ok(t.magic?)
|
||||
| ^^^^^^^^^^^^ help: try: `t.magic`
|
||||
|
||||
error: Question mark operator is useless here
|
||||
--> $DIR/needless_question_mark.rs:79:16
|
||||
--> $DIR/needless_question_mark.rs:85:16
|
||||
|
|
||||
LL | return Ok(t.magic?);
|
||||
| ^^^^^^^^^^^^ help: try: `t.magic`
|
||||
|
||||
error: Question mark operator is useless here
|
||||
--> $DIR/needless_question_mark.rs:132:9
|
||||
--> $DIR/needless_question_mark.rs:138:9
|
||||
|
|
||||
LL | Ok(to.magic?) // should be triggered
|
||||
| ^^^^^^^^^^^^^ help: try: `to.magic`
|
||||
|
||||
error: Question mark operator is useless here
|
||||
--> $DIR/needless_question_mark.rs:148:9
|
||||
--> $DIR/needless_question_mark.rs:154:9
|
||||
|
|
||||
LL | Some(to.magic?) // should be triggered
|
||||
| ^^^^^^^^^^^^^^^ help: try: `to.magic`
|
||||
|
||||
error: Question mark operator is useless here
|
||||
--> $DIR/needless_question_mark.rs:156:9
|
||||
--> $DIR/needless_question_mark.rs:162:9
|
||||
|
|
||||
LL | Ok(to.magic?) // should be triggered
|
||||
| ^^^^^^^^^^^^^ help: try: `to.magic`
|
||||
|
@ -101,6 +101,25 @@ fn test_return_in_macro() {
|
||||
needed_return!(0);
|
||||
}
|
||||
|
||||
mod issue6501 {
|
||||
fn foo(bar: Result<(), ()>) {
|
||||
bar.unwrap_or_else(|_| {})
|
||||
}
|
||||
|
||||
fn test_closure() {
|
||||
let _ = || {
|
||||
|
||||
};
|
||||
let _ = || {};
|
||||
}
|
||||
|
||||
struct Foo;
|
||||
#[allow(clippy::unnecessary_lazy_evaluations)]
|
||||
fn bar(res: Result<Foo, u8>) -> Foo {
|
||||
res.unwrap_or_else(|_| Foo)
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let _ = test_end_of_fn();
|
||||
let _ = test_no_semicolon();
|
||||
|
@ -101,6 +101,25 @@ fn test_return_in_macro() {
|
||||
needed_return!(0);
|
||||
}
|
||||
|
||||
mod issue6501 {
|
||||
fn foo(bar: Result<(), ()>) {
|
||||
bar.unwrap_or_else(|_| return)
|
||||
}
|
||||
|
||||
fn test_closure() {
|
||||
let _ = || {
|
||||
return;
|
||||
};
|
||||
let _ = || return;
|
||||
}
|
||||
|
||||
struct Foo;
|
||||
#[allow(clippy::unnecessary_lazy_evaluations)]
|
||||
fn bar(res: Result<Foo, u8>) -> Foo {
|
||||
res.unwrap_or_else(|_| return Foo)
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let _ = test_end_of_fn();
|
||||
let _ = test_no_semicolon();
|
||||
|
@ -84,5 +84,29 @@ error: unneeded `return` statement
|
||||
LL | return String::new();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::new()`
|
||||
|
||||
error: aborting due to 14 previous errors
|
||||
error: unneeded `return` statement
|
||||
--> $DIR/needless_return.rs:106:32
|
||||
|
|
||||
LL | bar.unwrap_or_else(|_| return)
|
||||
| ^^^^^^ help: replace `return` with an empty block: `{}`
|
||||
|
||||
error: unneeded `return` statement
|
||||
--> $DIR/needless_return.rs:111:13
|
||||
|
|
||||
LL | return;
|
||||
| ^^^^^^^ help: remove `return`
|
||||
|
||||
error: unneeded `return` statement
|
||||
--> $DIR/needless_return.rs:113:20
|
||||
|
|
||||
LL | let _ = || return;
|
||||
| ^^^^^^ help: replace `return` with an empty block: `{}`
|
||||
|
||||
error: unneeded `return` statement
|
||||
--> $DIR/needless_return.rs:119:32
|
||||
|
|
||||
LL | res.unwrap_or_else(|_| return Foo)
|
||||
| ^^^^^^^^^^ help: remove `return`: `Foo`
|
||||
|
||||
error: aborting due to 18 previous errors
|
||||
|
||||
|
@ -17,14 +17,14 @@ fn main() {
|
||||
println!("{bar:8} {foo:>8}", foo = "hello", bar = "world");
|
||||
println!("{number:>width$}", number = 1, width = 6);
|
||||
println!("{number:>0width$}", number = 1, width = 6);
|
||||
println!("{} of {:b} people know binary, the other half doesn't", 1, 2);
|
||||
println!("10 / 4 is {}", 2.5);
|
||||
println!("2 + 1 = {}", 3);
|
||||
|
||||
// these should throw warnings
|
||||
println!("{} of {:b} people know binary, the other half doesn't", 1, 2);
|
||||
print!("Hello {}", "world");
|
||||
println!("Hello {} {}", world, "world");
|
||||
println!("Hello {}", "world");
|
||||
println!("10 / 4 is {}", 2.5);
|
||||
println!("2 + 1 = {}", 3);
|
||||
|
||||
// positional args don't change the fact
|
||||
// that we're using a literal -- this should
|
||||
|
@ -1,41 +1,23 @@
|
||||
error: literal with an empty format string
|
||||
--> $DIR/print_literal.rs:22:71
|
||||
--> $DIR/print_literal.rs:25:24
|
||||
|
|
||||
LL | println!("{} of {:b} people know binary, the other half doesn't", 1, 2);
|
||||
| ^
|
||||
LL | print!("Hello {}", "world");
|
||||
| ^^^^^^^
|
||||
|
|
||||
= note: `-D clippy::print-literal` implied by `-D warnings`
|
||||
|
||||
error: literal with an empty format string
|
||||
--> $DIR/print_literal.rs:23:24
|
||||
|
|
||||
LL | print!("Hello {}", "world");
|
||||
| ^^^^^^^
|
||||
|
||||
error: literal with an empty format string
|
||||
--> $DIR/print_literal.rs:24:36
|
||||
--> $DIR/print_literal.rs:26:36
|
||||
|
|
||||
LL | println!("Hello {} {}", world, "world");
|
||||
| ^^^^^^^
|
||||
|
||||
error: literal with an empty format string
|
||||
--> $DIR/print_literal.rs:25:26
|
||||
--> $DIR/print_literal.rs:27:26
|
||||
|
|
||||
LL | println!("Hello {}", "world");
|
||||
| ^^^^^^^
|
||||
|
||||
error: literal with an empty format string
|
||||
--> $DIR/print_literal.rs:26:30
|
||||
|
|
||||
LL | println!("10 / 4 is {}", 2.5);
|
||||
| ^^^
|
||||
|
||||
error: literal with an empty format string
|
||||
--> $DIR/print_literal.rs:27:28
|
||||
|
|
||||
LL | println!("2 + 1 = {}", 3);
|
||||
| ^
|
||||
|
||||
error: literal with an empty format string
|
||||
--> $DIR/print_literal.rs:32:25
|
||||
|
|
||||
@ -84,5 +66,5 @@ error: literal with an empty format string
|
||||
LL | println!("{bar} {foo}", foo = "hello", bar = "world");
|
||||
| ^^^^^^^
|
||||
|
||||
error: aborting due to 14 previous errors
|
||||
error: aborting due to 11 previous errors
|
||||
|
||||
|
11
src/tools/clippy/tests/ui/redundant_slicing.rs
Normal file
11
src/tools/clippy/tests/ui/redundant_slicing.rs
Normal file
@ -0,0 +1,11 @@
|
||||
#![allow(unused)]
|
||||
#![warn(clippy::redundant_slicing)]
|
||||
|
||||
fn main() {
|
||||
let x: &[u32] = &[0];
|
||||
let err = &x[..];
|
||||
|
||||
let v = vec![0];
|
||||
let ok = &v[..];
|
||||
let err = &(&v[..])[..];
|
||||
}
|
16
src/tools/clippy/tests/ui/redundant_slicing.stderr
Normal file
16
src/tools/clippy/tests/ui/redundant_slicing.stderr
Normal file
@ -0,0 +1,16 @@
|
||||
error: redundant slicing of the whole range
|
||||
--> $DIR/redundant_slicing.rs:6:15
|
||||
|
|
||||
LL | let err = &x[..];
|
||||
| ^^^^^^ help: use the original slice instead: `x`
|
||||
|
|
||||
= note: `-D clippy::redundant-slicing` implied by `-D warnings`
|
||||
|
||||
error: redundant slicing of the whole range
|
||||
--> $DIR/redundant_slicing.rs:10:15
|
||||
|
|
||||
LL | let err = &(&v[..])[..];
|
||||
| ^^^^^^^^^^^^^ help: use the original slice instead: `(&v[..])`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
@ -101,3 +101,8 @@ pub(crate) struct DirSizes {
|
||||
pub(crate) numb_reg_cache_entries: u64,
|
||||
pub(crate) numb_reg_src_checkouts: u64,
|
||||
}
|
||||
|
||||
fn ignore_underscore_prefix() {
|
||||
let hello: ();
|
||||
let _hello: ();
|
||||
}
|
||||
|
@ -81,6 +81,62 @@ fn single_match_know_enum() {
|
||||
}
|
||||
}
|
||||
|
||||
// issue #173
|
||||
fn if_suggestion() {
|
||||
let x = "test";
|
||||
match x {
|
||||
"test" => println!(),
|
||||
_ => (),
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq)]
|
||||
enum Foo {
|
||||
A,
|
||||
B,
|
||||
C(u32),
|
||||
}
|
||||
|
||||
let x = Foo::A;
|
||||
match x {
|
||||
Foo::A => println!(),
|
||||
_ => (),
|
||||
}
|
||||
|
||||
const FOO_C: Foo = Foo::C(0);
|
||||
match x {
|
||||
FOO_C => println!(),
|
||||
_ => (),
|
||||
}
|
||||
|
||||
match &&x {
|
||||
Foo::A => println!(),
|
||||
_ => (),
|
||||
}
|
||||
|
||||
let x = &x;
|
||||
match &x {
|
||||
Foo::A => println!(),
|
||||
_ => (),
|
||||
}
|
||||
|
||||
enum Bar {
|
||||
A,
|
||||
B,
|
||||
}
|
||||
impl PartialEq for Bar {
|
||||
fn eq(&self, rhs: &Self) -> bool {
|
||||
matches!((self, rhs), (Self::A, Self::A) | (Self::B, Self::B))
|
||||
}
|
||||
}
|
||||
impl Eq for Bar {}
|
||||
|
||||
let x = Bar::A;
|
||||
match x {
|
||||
Bar::A => println!(),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! single_match {
|
||||
($num:literal) => {
|
||||
match $num {
|
||||
|
@ -1,4 +1,4 @@
|
||||
error: you seem to be trying to use match for destructuring a single pattern. Consider using `if let`
|
||||
error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
|
||||
--> $DIR/single_match.rs:8:5
|
||||
|
|
||||
LL | / match x {
|
||||
@ -17,7 +17,7 @@ LL | println!("{:?}", y);
|
||||
LL | };
|
||||
|
|
||||
|
||||
error: you seem to be trying to use match for destructuring a single pattern. Consider using `if let`
|
||||
error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
|
||||
--> $DIR/single_match.rs:16:5
|
||||
|
|
||||
LL | / match x {
|
||||
@ -29,7 +29,7 @@ LL | | _ => (),
|
||||
LL | | }
|
||||
| |_____^ help: try this: `if let Some(y) = x { println!("{:?}", y) }`
|
||||
|
||||
error: you seem to be trying to use match for destructuring a single pattern. Consider using `if let`
|
||||
error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
|
||||
--> $DIR/single_match.rs:25:5
|
||||
|
|
||||
LL | / match z {
|
||||
@ -38,7 +38,7 @@ LL | | _ => {},
|
||||
LL | | };
|
||||
| |_____^ help: try this: `if let (2..=3, 7..=9) = z { dummy() }`
|
||||
|
||||
error: you seem to be trying to use match for destructuring a single pattern. Consider using `if let`
|
||||
error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
|
||||
--> $DIR/single_match.rs:54:5
|
||||
|
|
||||
LL | / match x {
|
||||
@ -47,7 +47,7 @@ LL | | None => (),
|
||||
LL | | };
|
||||
| |_____^ help: try this: `if let Some(y) = x { dummy() }`
|
||||
|
||||
error: you seem to be trying to use match for destructuring a single pattern. Consider using `if let`
|
||||
error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
|
||||
--> $DIR/single_match.rs:59:5
|
||||
|
|
||||
LL | / match y {
|
||||
@ -56,7 +56,7 @@ LL | | Err(..) => (),
|
||||
LL | | };
|
||||
| |_____^ help: try this: `if let Ok(y) = y { dummy() }`
|
||||
|
||||
error: you seem to be trying to use match for destructuring a single pattern. Consider using `if let`
|
||||
error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
|
||||
--> $DIR/single_match.rs:66:5
|
||||
|
|
||||
LL | / match c {
|
||||
@ -65,5 +65,59 @@ LL | | Cow::Owned(..) => (),
|
||||
LL | | };
|
||||
| |_____^ help: try this: `if let Cow::Borrowed(..) = c { dummy() }`
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
error: you seem to be trying to use `match` for an equality check. Consider using `if`
|
||||
--> $DIR/single_match.rs:87:5
|
||||
|
|
||||
LL | / match x {
|
||||
LL | | "test" => println!(),
|
||||
LL | | _ => (),
|
||||
LL | | }
|
||||
| |_____^ help: try this: `if x == "test" { println!() }`
|
||||
|
||||
error: you seem to be trying to use `match` for an equality check. Consider using `if`
|
||||
--> $DIR/single_match.rs:100:5
|
||||
|
|
||||
LL | / match x {
|
||||
LL | | Foo::A => println!(),
|
||||
LL | | _ => (),
|
||||
LL | | }
|
||||
| |_____^ help: try this: `if x == Foo::A { println!() }`
|
||||
|
||||
error: you seem to be trying to use `match` for an equality check. Consider using `if`
|
||||
--> $DIR/single_match.rs:106:5
|
||||
|
|
||||
LL | / match x {
|
||||
LL | | FOO_C => println!(),
|
||||
LL | | _ => (),
|
||||
LL | | }
|
||||
| |_____^ help: try this: `if x == FOO_C { println!() }`
|
||||
|
||||
error: you seem to be trying to use `match` for an equality check. Consider using `if`
|
||||
--> $DIR/single_match.rs:111:5
|
||||
|
|
||||
LL | / match &&x {
|
||||
LL | | Foo::A => println!(),
|
||||
LL | | _ => (),
|
||||
LL | | }
|
||||
| |_____^ help: try this: `if x == Foo::A { println!() }`
|
||||
|
||||
error: you seem to be trying to use `match` for an equality check. Consider using `if`
|
||||
--> $DIR/single_match.rs:117:5
|
||||
|
|
||||
LL | / match &x {
|
||||
LL | | Foo::A => println!(),
|
||||
LL | | _ => (),
|
||||
LL | | }
|
||||
| |_____^ help: try this: `if x == &Foo::A { println!() }`
|
||||
|
||||
error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
|
||||
--> $DIR/single_match.rs:134:5
|
||||
|
|
||||
LL | / match x {
|
||||
LL | | Bar::A => println!(),
|
||||
LL | | _ => (),
|
||||
LL | | }
|
||||
| |_____^ help: try this: `if let Bar::A = x { println!() }`
|
||||
|
||||
error: aborting due to 12 previous errors
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
error: you seem to be trying to use match for destructuring a single pattern. Consider using `if let`
|
||||
error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
|
||||
--> $DIR/single_match_else.rs:14:5
|
||||
|
|
||||
LL | / match ExprNode::Butterflies {
|
||||
@ -19,7 +19,7 @@ LL | None
|
||||
LL | }
|
||||
|
|
||||
|
||||
error: you seem to be trying to use match for destructuring a single pattern. Consider using `if let`
|
||||
error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
|
||||
--> $DIR/single_match_else.rs:70:5
|
||||
|
|
||||
LL | / match Some(1) {
|
||||
@ -39,7 +39,7 @@ LL | return
|
||||
LL | }
|
||||
|
|
||||
|
||||
error: you seem to be trying to use match for destructuring a single pattern. Consider using `if let`
|
||||
error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
|
||||
--> $DIR/single_match_else.rs:79:5
|
||||
|
|
||||
LL | / match Some(1) {
|
||||
|
@ -0,0 +1,37 @@
|
||||
#![warn(clippy::size_of_in_element_count)]
|
||||
#![allow(clippy::ptr_offset_with_cast)]
|
||||
|
||||
use std::mem::{size_of, size_of_val};
|
||||
use std::ptr::{copy, copy_nonoverlapping, write_bytes};
|
||||
|
||||
fn main() {
|
||||
const SIZE: usize = 128;
|
||||
const HALF_SIZE: usize = SIZE / 2;
|
||||
const DOUBLE_SIZE: usize = SIZE * 2;
|
||||
let mut x = [2u8; SIZE];
|
||||
let mut y = [2u8; SIZE];
|
||||
|
||||
// Count expression involving multiplication of size_of (Should trigger the lint)
|
||||
unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::<u8>() * SIZE) };
|
||||
|
||||
// Count expression involving nested multiplications of size_of (Should trigger the lint)
|
||||
unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), HALF_SIZE * size_of_val(&x[0]) * 2) };
|
||||
|
||||
// Count expression involving divisions of size_of (Should trigger the lint)
|
||||
unsafe { copy(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE * size_of::<u8>() / 2) };
|
||||
|
||||
// Count expression involving divisions by size_of (Should not trigger the lint)
|
||||
unsafe { copy(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE / size_of::<u8>()) };
|
||||
|
||||
// Count expression involving divisions by multiple size_of (Should not trigger the lint)
|
||||
unsafe { copy(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE / (2 * size_of::<u8>())) };
|
||||
|
||||
// Count expression involving recursive divisions by size_of (Should trigger the lint)
|
||||
unsafe { copy(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE / (2 / size_of::<u8>())) };
|
||||
|
||||
// No size_of calls (Should not trigger the lint)
|
||||
unsafe { copy(x.as_ptr(), y.as_mut_ptr(), SIZE) };
|
||||
|
||||
// Different types for pointee and size_of (Should not trigger the lint)
|
||||
unsafe { y.as_mut_ptr().write_bytes(0u8, size_of::<u16>() / 2 * SIZE) };
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
error: found a count of bytes instead of a count of elements of `T`
|
||||
--> $DIR/expressions.rs:15:62
|
||||
|
|
||||
LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::<u8>() * SIZE) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `-D clippy::size-of-in-element-count` implied by `-D warnings`
|
||||
= help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
|
||||
|
||||
error: found a count of bytes instead of a count of elements of `T`
|
||||
--> $DIR/expressions.rs:18:62
|
||||
|
|
||||
LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), HALF_SIZE * size_of_val(&x[0]) * 2) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
|
||||
|
||||
error: found a count of bytes instead of a count of elements of `T`
|
||||
--> $DIR/expressions.rs:21:47
|
||||
|
|
||||
LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE * size_of::<u8>() / 2) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
|
||||
|
||||
error: found a count of bytes instead of a count of elements of `T`
|
||||
--> $DIR/expressions.rs:30:47
|
||||
|
|
||||
LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE / (2 / size_of::<u8>())) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
@ -43,19 +43,4 @@ fn main() {
|
||||
y.as_mut_ptr().wrapping_add(size_of::<u8>());
|
||||
unsafe { y.as_ptr().offset(size_of::<u8>() as isize) };
|
||||
y.as_mut_ptr().wrapping_offset(size_of::<u8>() as isize);
|
||||
|
||||
// Count expression involving multiplication of size_of (Should trigger the lint)
|
||||
unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::<u8>() * SIZE) };
|
||||
|
||||
// Count expression involving nested multiplications of size_of (Should trigger the lint)
|
||||
unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), HALF_SIZE * size_of_val(&x[0]) * 2) };
|
||||
|
||||
// Count expression involving divisions of size_of (Should trigger the lint)
|
||||
unsafe { copy(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE * size_of::<u8>() / 2) };
|
||||
|
||||
// No size_of calls (Should not trigger the lint)
|
||||
unsafe { copy(x.as_ptr(), y.as_mut_ptr(), SIZE) };
|
||||
|
||||
// Different types for pointee and size_of (Should not trigger the lint)
|
||||
unsafe { y.as_mut_ptr().write_bytes(0u8, size_of::<u16>() / 2 * SIZE) };
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
error: found a count of bytes instead of a count of elements of `T`
|
||||
--> $DIR/size_of_in_element_count.rs:18:68
|
||||
--> $DIR/functions.rs:18:68
|
||||
|
|
||||
LL | unsafe { copy_nonoverlapping::<u8>(x.as_ptr(), y.as_mut_ptr(), size_of::<u8>()) };
|
||||
| ^^^^^^^^^^^^^^^
|
||||
@ -8,7 +8,7 @@ LL | unsafe { copy_nonoverlapping::<u8>(x.as_ptr(), y.as_mut_ptr(), size_of:
|
||||
= help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
|
||||
|
||||
error: found a count of bytes instead of a count of elements of `T`
|
||||
--> $DIR/size_of_in_element_count.rs:19:62
|
||||
--> $DIR/functions.rs:19:62
|
||||
|
|
||||
LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0])) };
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
@ -16,7 +16,7 @@ LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x
|
||||
= help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
|
||||
|
||||
error: found a count of bytes instead of a count of elements of `T`
|
||||
--> $DIR/size_of_in_element_count.rs:21:49
|
||||
--> $DIR/functions.rs:21:49
|
||||
|
|
||||
LL | unsafe { x.as_ptr().copy_to(y.as_mut_ptr(), size_of::<u8>()) };
|
||||
| ^^^^^^^^^^^^^^^
|
||||
@ -24,7 +24,7 @@ LL | unsafe { x.as_ptr().copy_to(y.as_mut_ptr(), size_of::<u8>()) };
|
||||
= help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
|
||||
|
||||
error: found a count of bytes instead of a count of elements of `T`
|
||||
--> $DIR/size_of_in_element_count.rs:22:64
|
||||
--> $DIR/functions.rs:22:64
|
||||
|
|
||||
LL | unsafe { x.as_ptr().copy_to_nonoverlapping(y.as_mut_ptr(), size_of::<u8>()) };
|
||||
| ^^^^^^^^^^^^^^^
|
||||
@ -32,7 +32,7 @@ LL | unsafe { x.as_ptr().copy_to_nonoverlapping(y.as_mut_ptr(), size_of::<u8
|
||||
= help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
|
||||
|
||||
error: found a count of bytes instead of a count of elements of `T`
|
||||
--> $DIR/size_of_in_element_count.rs:23:51
|
||||
--> $DIR/functions.rs:23:51
|
||||
|
|
||||
LL | unsafe { y.as_mut_ptr().copy_from(x.as_ptr(), size_of::<u8>()) };
|
||||
| ^^^^^^^^^^^^^^^
|
||||
@ -40,7 +40,7 @@ LL | unsafe { y.as_mut_ptr().copy_from(x.as_ptr(), size_of::<u8>()) };
|
||||
= help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
|
||||
|
||||
error: found a count of bytes instead of a count of elements of `T`
|
||||
--> $DIR/size_of_in_element_count.rs:24:66
|
||||
--> $DIR/functions.rs:24:66
|
||||
|
|
||||
LL | unsafe { y.as_mut_ptr().copy_from_nonoverlapping(x.as_ptr(), size_of::<u8>()) };
|
||||
| ^^^^^^^^^^^^^^^
|
||||
@ -48,7 +48,7 @@ LL | unsafe { y.as_mut_ptr().copy_from_nonoverlapping(x.as_ptr(), size_of::<
|
||||
= help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
|
||||
|
||||
error: found a count of bytes instead of a count of elements of `T`
|
||||
--> $DIR/size_of_in_element_count.rs:26:47
|
||||
--> $DIR/functions.rs:26:47
|
||||
|
|
||||
LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of::<u8>()) };
|
||||
| ^^^^^^^^^^^^^^^
|
||||
@ -56,7 +56,7 @@ LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of::<u8>()) };
|
||||
= help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
|
||||
|
||||
error: found a count of bytes instead of a count of elements of `T`
|
||||
--> $DIR/size_of_in_element_count.rs:27:47
|
||||
--> $DIR/functions.rs:27:47
|
||||
|
|
||||
LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0])) };
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
@ -64,7 +64,7 @@ LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0])) };
|
||||
= help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
|
||||
|
||||
error: found a count of bytes instead of a count of elements of `T`
|
||||
--> $DIR/size_of_in_element_count.rs:29:46
|
||||
--> $DIR/functions.rs:29:46
|
||||
|
|
||||
LL | unsafe { y.as_mut_ptr().write_bytes(0u8, size_of::<u8>() * SIZE) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -72,7 +72,7 @@ LL | unsafe { y.as_mut_ptr().write_bytes(0u8, size_of::<u8>() * SIZE) };
|
||||
= help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
|
||||
|
||||
error: found a count of bytes instead of a count of elements of `T`
|
||||
--> $DIR/size_of_in_element_count.rs:30:47
|
||||
--> $DIR/functions.rs:30:47
|
||||
|
|
||||
LL | unsafe { write_bytes(y.as_mut_ptr(), 0u8, size_of::<u8>() * SIZE) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -80,7 +80,7 @@ LL | unsafe { write_bytes(y.as_mut_ptr(), 0u8, size_of::<u8>() * SIZE) };
|
||||
= help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
|
||||
|
||||
error: found a count of bytes instead of a count of elements of `T`
|
||||
--> $DIR/size_of_in_element_count.rs:32:66
|
||||
--> $DIR/functions.rs:32:66
|
||||
|
|
||||
LL | unsafe { swap_nonoverlapping(y.as_mut_ptr(), x.as_mut_ptr(), size_of::<u8>() * SIZE) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -88,7 +88,7 @@ LL | unsafe { swap_nonoverlapping(y.as_mut_ptr(), x.as_mut_ptr(), size_of::<
|
||||
= help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
|
||||
|
||||
error: found a count of bytes instead of a count of elements of `T`
|
||||
--> $DIR/size_of_in_element_count.rs:34:46
|
||||
--> $DIR/functions.rs:34:46
|
||||
|
|
||||
LL | slice_from_raw_parts_mut(y.as_mut_ptr(), size_of::<u8>() * SIZE);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -96,7 +96,7 @@ LL | slice_from_raw_parts_mut(y.as_mut_ptr(), size_of::<u8>() * SIZE);
|
||||
= help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
|
||||
|
||||
error: found a count of bytes instead of a count of elements of `T`
|
||||
--> $DIR/size_of_in_element_count.rs:35:38
|
||||
--> $DIR/functions.rs:35:38
|
||||
|
|
||||
LL | slice_from_raw_parts(y.as_ptr(), size_of::<u8>() * SIZE);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -104,7 +104,7 @@ LL | slice_from_raw_parts(y.as_ptr(), size_of::<u8>() * SIZE);
|
||||
= help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
|
||||
|
||||
error: found a count of bytes instead of a count of elements of `T`
|
||||
--> $DIR/size_of_in_element_count.rs:37:49
|
||||
--> $DIR/functions.rs:37:49
|
||||
|
|
||||
LL | unsafe { from_raw_parts_mut(y.as_mut_ptr(), size_of::<u8>() * SIZE) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -112,7 +112,7 @@ LL | unsafe { from_raw_parts_mut(y.as_mut_ptr(), size_of::<u8>() * SIZE) };
|
||||
= help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
|
||||
|
||||
error: found a count of bytes instead of a count of elements of `T`
|
||||
--> $DIR/size_of_in_element_count.rs:38:41
|
||||
--> $DIR/functions.rs:38:41
|
||||
|
|
||||
LL | unsafe { from_raw_parts(y.as_ptr(), size_of::<u8>() * SIZE) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -120,7 +120,7 @@ LL | unsafe { from_raw_parts(y.as_ptr(), size_of::<u8>() * SIZE) };
|
||||
= help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
|
||||
|
||||
error: found a count of bytes instead of a count of elements of `T`
|
||||
--> $DIR/size_of_in_element_count.rs:40:33
|
||||
--> $DIR/functions.rs:40:33
|
||||
|
|
||||
LL | unsafe { y.as_mut_ptr().sub(size_of::<u8>()) };
|
||||
| ^^^^^^^^^^^^^^^
|
||||
@ -128,7 +128,7 @@ LL | unsafe { y.as_mut_ptr().sub(size_of::<u8>()) };
|
||||
= help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
|
||||
|
||||
error: found a count of bytes instead of a count of elements of `T`
|
||||
--> $DIR/size_of_in_element_count.rs:41:29
|
||||
--> $DIR/functions.rs:41:29
|
||||
|
|
||||
LL | y.as_ptr().wrapping_sub(size_of::<u8>());
|
||||
| ^^^^^^^^^^^^^^^
|
||||
@ -136,7 +136,7 @@ LL | y.as_ptr().wrapping_sub(size_of::<u8>());
|
||||
= help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
|
||||
|
||||
error: found a count of bytes instead of a count of elements of `T`
|
||||
--> $DIR/size_of_in_element_count.rs:42:29
|
||||
--> $DIR/functions.rs:42:29
|
||||
|
|
||||
LL | unsafe { y.as_ptr().add(size_of::<u8>()) };
|
||||
| ^^^^^^^^^^^^^^^
|
||||
@ -144,7 +144,7 @@ LL | unsafe { y.as_ptr().add(size_of::<u8>()) };
|
||||
= help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
|
||||
|
||||
error: found a count of bytes instead of a count of elements of `T`
|
||||
--> $DIR/size_of_in_element_count.rs:43:33
|
||||
--> $DIR/functions.rs:43:33
|
||||
|
|
||||
LL | y.as_mut_ptr().wrapping_add(size_of::<u8>());
|
||||
| ^^^^^^^^^^^^^^^
|
||||
@ -152,7 +152,7 @@ LL | y.as_mut_ptr().wrapping_add(size_of::<u8>());
|
||||
= help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
|
||||
|
||||
error: found a count of bytes instead of a count of elements of `T`
|
||||
--> $DIR/size_of_in_element_count.rs:44:32
|
||||
--> $DIR/functions.rs:44:32
|
||||
|
|
||||
LL | unsafe { y.as_ptr().offset(size_of::<u8>() as isize) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -160,36 +160,12 @@ LL | unsafe { y.as_ptr().offset(size_of::<u8>() as isize) };
|
||||
= help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
|
||||
|
||||
error: found a count of bytes instead of a count of elements of `T`
|
||||
--> $DIR/size_of_in_element_count.rs:45:36
|
||||
--> $DIR/functions.rs:45:36
|
||||
|
|
||||
LL | y.as_mut_ptr().wrapping_offset(size_of::<u8>() as isize);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
|
||||
|
||||
error: found a count of bytes instead of a count of elements of `T`
|
||||
--> $DIR/size_of_in_element_count.rs:48:62
|
||||
|
|
||||
LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::<u8>() * SIZE) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
|
||||
|
||||
error: found a count of bytes instead of a count of elements of `T`
|
||||
--> $DIR/size_of_in_element_count.rs:51:62
|
||||
|
|
||||
LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), HALF_SIZE * size_of_val(&x[0]) * 2) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
|
||||
|
||||
error: found a count of bytes instead of a count of elements of `T`
|
||||
--> $DIR/size_of_in_element_count.rs:54:47
|
||||
|
|
||||
LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE * size_of::<u8>() / 2) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type
|
||||
|
||||
error: aborting due to 24 previous errors
|
||||
error: aborting due to 21 previous errors
|
||||
|
@ -1,46 +1,59 @@
|
||||
error: used sort instead of sort_unstable to sort primitive type `i32`
|
||||
error: used `sort` on primitive type `i32`
|
||||
--> $DIR/stable_sort_primitive.rs:7:5
|
||||
|
|
||||
LL | vec.sort();
|
||||
| ^^^^^^^^^^ help: try: `vec.sort_unstable()`
|
||||
|
|
||||
= note: `-D clippy::stable-sort-primitive` implied by `-D warnings`
|
||||
= note: an unstable sort would perform faster without any observable difference for this data type
|
||||
|
||||
error: used sort instead of sort_unstable to sort primitive type `bool`
|
||||
error: used `sort` on primitive type `bool`
|
||||
--> $DIR/stable_sort_primitive.rs:9:5
|
||||
|
|
||||
LL | vec.sort();
|
||||
| ^^^^^^^^^^ help: try: `vec.sort_unstable()`
|
||||
|
|
||||
= note: an unstable sort would perform faster without any observable difference for this data type
|
||||
|
||||
error: used sort instead of sort_unstable to sort primitive type `char`
|
||||
error: used `sort` on primitive type `char`
|
||||
--> $DIR/stable_sort_primitive.rs:11:5
|
||||
|
|
||||
LL | vec.sort();
|
||||
| ^^^^^^^^^^ help: try: `vec.sort_unstable()`
|
||||
|
|
||||
= note: an unstable sort would perform faster without any observable difference for this data type
|
||||
|
||||
error: used sort instead of sort_unstable to sort primitive type `str`
|
||||
error: used `sort` on primitive type `str`
|
||||
--> $DIR/stable_sort_primitive.rs:13:5
|
||||
|
|
||||
LL | vec.sort();
|
||||
| ^^^^^^^^^^ help: try: `vec.sort_unstable()`
|
||||
|
|
||||
= note: an unstable sort would perform faster without any observable difference for this data type
|
||||
|
||||
error: used sort instead of sort_unstable to sort primitive type `tuple`
|
||||
error: used `sort` on primitive type `tuple`
|
||||
--> $DIR/stable_sort_primitive.rs:15:5
|
||||
|
|
||||
LL | vec.sort();
|
||||
| ^^^^^^^^^^ help: try: `vec.sort_unstable()`
|
||||
|
|
||||
= note: an unstable sort would perform faster without any observable difference for this data type
|
||||
|
||||
error: used sort instead of sort_unstable to sort primitive type `array`
|
||||
error: used `sort` on primitive type `array`
|
||||
--> $DIR/stable_sort_primitive.rs:17:5
|
||||
|
|
||||
LL | vec.sort();
|
||||
| ^^^^^^^^^^ help: try: `vec.sort_unstable()`
|
||||
|
|
||||
= note: an unstable sort would perform faster without any observable difference for this data type
|
||||
|
||||
error: used sort instead of sort_unstable to sort primitive type `i32`
|
||||
error: used `sort` on primitive type `i32`
|
||||
--> $DIR/stable_sort_primitive.rs:19:5
|
||||
|
|
||||
LL | arr.sort();
|
||||
| ^^^^^^^^^^ help: try: `arr.sort_unstable()`
|
||||
|
|
||||
= note: an unstable sort would perform faster without any observable difference for this data type
|
||||
|
||||
error: aborting due to 7 previous errors
|
||||
|
||||
|
@ -27,7 +27,7 @@ fn buggy_ab_cmp(s1: &S, s2: &S) -> bool {
|
||||
s1.a < s2.a && s1.a < s2.b
|
||||
}
|
||||
|
||||
struct SAOnly {
|
||||
struct SaOnly {
|
||||
a: i32,
|
||||
}
|
||||
|
||||
@ -37,13 +37,13 @@ impl S {
|
||||
}
|
||||
}
|
||||
|
||||
fn do_not_give_bad_suggestions_for_this_unusual_expr(s1: &S, s2: &SAOnly) -> bool {
|
||||
fn do_not_give_bad_suggestions_for_this_unusual_expr(s1: &S, s2: &SaOnly) -> bool {
|
||||
// This is superficially similar to `buggy_ab_cmp`, but we should not suggest
|
||||
// `s2.b` since that is invalid.
|
||||
s1.a < s2.a && s1.a() < s1.b
|
||||
}
|
||||
|
||||
fn do_not_give_bad_suggestions_for_this_macro_expr(s1: &S, s2: &SAOnly) -> bool {
|
||||
fn do_not_give_bad_suggestions_for_this_macro_expr(s1: &S, s2: &SaOnly) -> bool {
|
||||
macro_rules! s1 {
|
||||
() => {
|
||||
S {
|
||||
@ -60,7 +60,7 @@ fn do_not_give_bad_suggestions_for_this_macro_expr(s1: &S, s2: &SAOnly) -> bool
|
||||
s1.a < s2.a && s1!().a < s1.b
|
||||
}
|
||||
|
||||
fn do_not_give_bad_suggestions_for_this_incorrect_expr(s1: &S, s2: &SAOnly) -> bool {
|
||||
fn do_not_give_bad_suggestions_for_this_incorrect_expr(s1: &S, s2: &SaOnly) -> bool {
|
||||
// There's two `s1.b`, but we should not suggest `s2.b` since that is invalid
|
||||
s1.a < s2.a && s1.b < s1.b
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user