diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md index c1032204a22cb..7c79fe88816f1 100644 --- a/src/tools/clippy/CHANGELOG.md +++ b/src/tools/clippy/CHANGELOG.md @@ -1877,6 +1877,7 @@ Released 2018-09-13 [`box_vec`]: https://rust-lang.github.io/rust-clippy/master/index.html#box_vec [`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 +[`bytes_nth`]: https://rust-lang.github.io/rust-clippy/master/index.html#bytes_nth [`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 @@ -1955,6 +1956,7 @@ Released 2018-09-13 [`field_reassign_with_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#field_reassign_with_default [`filetype_is_file`]: https://rust-lang.github.io/rust-clippy/master/index.html#filetype_is_file [`filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_map +[`filter_map_identity`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_map_identity [`filter_map_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_map_next [`filter_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_next [`find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#find_map @@ -2039,6 +2041,7 @@ Released 2018-09-13 [`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_flatten`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_flatten [`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 @@ -2184,6 +2187,7 @@ Released 2018-09-13 [`same_item_push`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_item_push [`search_is_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#search_is_some [`self_assignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#self_assignment +[`semicolon_if_nothing_returned`]: https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_if_nothing_returned [`serde_api_misuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#serde_api_misuse [`shadow_reuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_reuse [`shadow_same`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_same diff --git a/src/tools/clippy/clippy_dev/Cargo.toml b/src/tools/clippy/clippy_dev/Cargo.toml index f48c1ee5ea265..5ac96e2210c89 100644 --- a/src/tools/clippy/clippy_dev/Cargo.toml +++ b/src/tools/clippy/clippy_dev/Cargo.toml @@ -9,6 +9,7 @@ edition = "2018" bytecount = "0.6" clap = "2.33" flate2 = { version = "1.0.19", optional = true } +fs_extra = { version = "1.2.0", optional = true } itertools = "0.9" opener = "0.4" regex = "1" @@ -21,5 +22,5 @@ ureq = { version = "2.0.0-rc3", optional = true } walkdir = "2" [features] -lintcheck = ["flate2", "serde_json", "tar", "toml", "ureq", "serde"] +lintcheck = ["flate2", "serde_json", "tar", "toml", "ureq", "serde", "fs_extra"] deny-warnings = [] diff --git a/src/tools/clippy/clippy_dev/README.md b/src/tools/clippy/clippy_dev/README.md new file mode 100644 index 0000000000000..3846e8bd4ccb7 --- /dev/null +++ b/src/tools/clippy/clippy_dev/README.md @@ -0,0 +1,28 @@ +# Clippy Dev Tool + +The Clippy Dev Tool is a tool to ease Clippy development, similar to `rustc`s `x.py`. + +Functionalities (incomplete): + +## `lintcheck` +Runs clippy on a fixed set of crates read from `clippy_dev/lintcheck_crates.toml` +and saves logs of the lint warnings into the repo. +We can then check the diff and spot new or disappearing warnings. + +From the repo root, run: +```` +cargo run --target-dir clippy_dev/target --package clippy_dev \ +--bin clippy_dev --manifest-path clippy_dev/Cargo.toml --features lintcheck -- lintcheck +```` +or +```` +cargo dev-lintcheck +```` + +By default the logs will be saved into `lintcheck-logs/lintcheck_crates_logs.txt`. + +You can set a custom sources.toml by adding `--crates-toml custom.toml` +where `custom.toml` must be a relative path from the repo root. + +The results will then be saved to `lintcheck-logs/custom_logs.toml`. + diff --git a/src/tools/clippy/clippy_dev/lintcheck_crates.toml b/src/tools/clippy/clippy_dev/lintcheck_crates.toml index 1fbf7930d3ecf..60e70ca4eb22b 100644 --- a/src/tools/clippy/clippy_dev/lintcheck_crates.toml +++ b/src/tools/clippy/clippy_dev/lintcheck_crates.toml @@ -1,20 +1,23 @@ [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'] +cargo = {name = "cargo", versions = ['0.49.0']} +iron = {name = "iron", versions = ['0.6.1']} +ripgrep = {name = "ripgrep", versions = ['12.1.1']} +xsv = {name = "xsv", versions = ['0.13.0']} +# commented out because of 173K clippy::match_same_arms msgs in language_type.rs +#tokei = { name = "tokei", versions = ['12.0.4']} +rayon = {name = "rayon", versions = ['1.5.0']} +serde = {name = "serde", versions = ['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'] +bitflags = {name = "bitflags", versions = ['1.2.1']} +# crash = {name = "clippy_crash", path = "/tmp/clippy_crash"} +libc = {name = "libc", versions = ['0.2.81']} +log = {name = "log", versions = ['0.4.11']} +proc-macro2 = {name = "proc-macro2", versions = ['1.0.24']} +puffin = {name = "puffin", git_url = "https://github.com/EmbarkStudios/puffin", git_hash = "02dd4a3"} +quote = {name = "quote", versions = ['1.0.7']} +rand = {name = "rand", versions = ['0.7.3']} +rand_core = {name = "rand_core", versions = ['0.6.0']} +regex = {name = "regex", versions = ['1.3.2']} +syn = {name = "syn", versions = ['1.0.54']} +unicode-xid = {name = "unicode-xid", versions = ['0.2.1']} diff --git a/src/tools/clippy/clippy_dev/src/lintcheck.rs b/src/tools/clippy/clippy_dev/src/lintcheck.rs index 785c692d3cb98..749a791b280e2 100644 --- a/src/tools/clippy/clippy_dev/src/lintcheck.rs +++ b/src/tools/clippy/clippy_dev/src/lintcheck.rs @@ -20,24 +20,31 @@ 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>, + crates: HashMap, } // 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 +#[derive(Debug, Serialize, Deserialize)] struct TomlCrate { name: String, - versions: Vec, + versions: Option>, + git_url: Option, + git_hash: Option, + path: Option, } -// represents an archive we download from crates.io +// represents an archive we download from crates.io, or a git repo, or a local repo #[derive(Debug, Serialize, Deserialize, Eq, Hash, PartialEq)] -struct CrateSource { - name: String, - version: String, +enum CrateSource { + CratesIo { name: String, version: String }, + Git { name: String, url: String, commit: String }, + Path { name: String, path: PathBuf }, } // represents the extracted sourcecode of a crate +// we actually don't need to special-case git repos here because it does not matter for clippy, yay! +// (clippy only needs a simple path) #[derive(Debug)] struct Crate { version: String, @@ -55,6 +62,7 @@ struct ClippyWarning { column: String, linttype: String, message: String, + ice: bool, } impl std::fmt::Display for ClippyWarning { @@ -69,40 +77,102 @@ impl std::fmt::Display for ClippyWarning { 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)), + match self { + CrateSource::CratesIo { name, version } => { + 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", name, version); + println!("Downloading and extracting {} {} from {}", name, 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", name, 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: version.clone(), + name: name.clone(), + path: extract_dir.join(format!("{}-{}/", name, version)), + } + }, + CrateSource::Git { name, url, commit } => { + let repo_path = { + let mut repo_path = PathBuf::from("target/lintcheck/crates"); + // add a -git suffix in case we have the same crate from crates.io and a git repo + repo_path.push(format!("{}-git", name)); + repo_path + }; + // clone the repo if we have not done so + if !repo_path.is_dir() { + println!("Cloning {} and checking out {}", url, commit); + Command::new("git") + .arg("clone") + .arg(url) + .arg(&repo_path) + .output() + .expect("Failed to clone git repo!"); + } + // check out the commit/branch/whatever + Command::new("git") + .arg("checkout") + .arg(commit) + .output() + .expect("Failed to check out commit"); + + Crate { + version: commit.clone(), + name: name.clone(), + path: repo_path, + } + }, + CrateSource::Path { name, path } => { + use fs_extra::dir; + + // simply copy the entire directory into our target dir + let copy_dest = PathBuf::from("target/lintcheck/crates/"); + + // the source path of the crate we copied, ${copy_dest}/crate_name + let crate_root = copy_dest.join(name); // .../crates/local_crate + + if !crate_root.exists() { + println!("Copying {} to {}", path.display(), copy_dest.display()); + + dir::copy(path, ©_dest, &dir::CopyOptions::new()).expect(&format!( + "Failed to copy from {}, to {}", + path.display(), + crate_root.display() + )); + } else { + println!( + "Not copying {} to {}, destination already exists", + path.display(), + crate_root.display() + ); + } + + Crate { + version: String::from("local"), + name: name.clone(), + path: crate_root, + } + }, } } } @@ -114,7 +184,7 @@ impl Crate { let shared_target_dir = clippy_project_root().join("target/lintcheck/shared_target_dir/"); - let all_output = std::process::Command::new(cargo_clippy_path) + 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` @@ -128,14 +198,20 @@ impl Crate { ]) .current_dir(&self.path) .output() - .unwrap(); + .unwrap_or_else(|error| { + panic!( + "Encountered error:\n{:?}\ncargo_clippy_path: {}\ncrate path:{}\n", + error, + &cargo_clippy_path.display(), + &self.path.display() + ); + }); let stdout = String::from_utf8_lossy(&all_output.stdout); let output_lines = stdout.lines(); - //dbg!(&output_lines); let warnings: Vec = output_lines .into_iter() - // get all clippy warnings - .filter(|line| line.contains("clippy::")) + // get all clippy warnings and ICEs + .filter(|line| line.contains("clippy::") || line.contains("internal compiler error: ")) .map(|json_msg| parse_json_message(json_msg, &self)) .collect(); warnings @@ -150,8 +226,10 @@ fn build_clippy() { } // get a list of CrateSources we want to check from a "lintcheck_crates.toml" file. -fn read_crates() -> Vec { - let toml_path = PathBuf::from("clippy_dev/lintcheck_crates.toml"); +fn read_crates(toml_path: Option<&str>) -> (String, Vec) { + let toml_path = PathBuf::from(toml_path.unwrap_or("clippy_dev/lintcheck_crates.toml")); + // save it so that we can use the name of the sources.toml as name for the logfile later. + let toml_filename = toml_path.file_stem().unwrap().to_str().unwrap().to_string(); 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 = @@ -160,21 +238,52 @@ fn read_crates() -> Vec { let tomlcrates: Vec = crate_list .crates .into_iter() - .map(|(name, versions)| TomlCrate { name, versions }) + .map(|(_cratename, tomlcrate)| tomlcrate) .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 { + if let Some(ref path) = tk.path { + crate_sources.push(CrateSource::Path { + name: tk.name.clone(), + path: PathBuf::from(path), + }); + } + + // if we have multiple versions, save each one + if let Some(ref versions) = tk.versions { + versions.iter().for_each(|ver| { + crate_sources.push(CrateSource::CratesIo { + name: tk.name.clone(), + version: ver.to_string(), + }); + }) + } + // otherwise, we should have a git source + if tk.git_url.is_some() && tk.git_hash.is_some() { + crate_sources.push(CrateSource::Git { name: tk.name.clone(), - version: ver.to_string(), + url: tk.git_url.clone().unwrap(), + commit: tk.git_hash.clone().unwrap(), }); - }) + } + // if we have a version as well as a git data OR only one git data, something is funky + if tk.versions.is_some() && (tk.git_url.is_some() || tk.git_hash.is_some()) + || tk.git_hash.is_some() != tk.git_url.is_some() + { + eprintln!("tomlkrate: {:?}", tk); + if tk.git_hash.is_some() != tk.git_url.is_some() { + panic!("Error: Encountered TomlCrate with only one of git_hash and git_url!"); + } + if tk.path.is_some() && (tk.git_hash.is_some() || tk.versions.is_some()) { + panic!("Error: TomlCrate can only have one of 'git_.*', 'version' or 'path' fields"); + } + unreachable!("Failed to translate TomlCrate into CrateSource!"); + } }); - crate_sources + (toml_filename, crate_sources) } // extract interesting data from a json lint message @@ -198,6 +307,7 @@ fn parse_json_message(json_message: &str, krate: &Crate) -> ClippyWarning { .into(), linttype: jmsg["message"]["code"]["code"].to_string().trim_matches('"').into(), message: jmsg["message"]["message"].to_string().trim_matches('"').into(), + ice: json_message.contains("internal compiler error: "), } } @@ -225,11 +335,18 @@ pub fn run(clap_config: &ArgMatches) { // 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 (filename, crates) = read_crates(clap_config.value_of("crates-toml")); let clippy_warnings: Vec = 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) { + // if we don't have the specified crate in the .toml, throw an error + if !crates.iter().any(|krate| { + let name = match krate { + CrateSource::CratesIo { name, .. } => name, + CrateSource::Git { name, .. } => name, + CrateSource::Path { name, .. } => name, + }; + name == only_one_crate + }) { eprintln!( "ERROR: could not find crate '{}' in clippy_dev/lintcheck_crates.toml", only_one_crate @@ -257,6 +374,13 @@ pub fn run(clap_config: &ArgMatches) { // generate some stats: + // grab crashes/ICEs, save the crate name and the ice message + let ices: Vec<(&String, &String)> = clippy_warnings + .iter() + .filter(|warning| warning.ice) + .map(|w| (&w.crate_name, &w.message)) + .collect(); + // count lint type occurrences let mut counter: HashMap<&String, usize> = HashMap::new(); clippy_warnings @@ -282,5 +406,10 @@ pub fn run(clap_config: &ArgMatches) { // 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(); + text.push_str("ICEs:\n"); + ices.iter() + .for_each(|(cratename, msg)| text.push_str(&format!("{}: '{}'", cratename, msg))); + + let file = format!("lintcheck-logs/{}_logs.txt", filename); + write(file, text).unwrap(); } diff --git a/src/tools/clippy/clippy_dev/src/main.rs b/src/tools/clippy/clippy_dev/src/main.rs index e7a298a37e17a..5dbd46935a59a 100644 --- a/src/tools/clippy/clippy_dev/src/main.rs +++ b/src/tools/clippy/clippy_dev/src/main.rs @@ -62,6 +62,13 @@ fn get_clap_config<'a>() -> ArgMatches<'a> { .value_name("CRATE") .long("only") .help("only process a single crate of the list"), + ) + .arg( + Arg::with_name("crates-toml") + .takes_value(true) + .value_name("CRATES-SOURCES-TOML-PATH") + .long("crates-toml") + .help("set the path for a crates.toml where lintcheck should read the sources from"), ); let app = App::new("Clippy developer tooling") diff --git a/src/tools/clippy/clippy_dev/src/ra_setup.rs b/src/tools/clippy/clippy_dev/src/ra_setup.rs index a3c329b578b20..d0e2193ddc5e5 100644 --- a/src/tools/clippy/clippy_dev/src/ra_setup.rs +++ b/src/tools/clippy/clippy_dev/src/ra_setup.rs @@ -13,7 +13,9 @@ use std::path::{Path, PathBuf}; /// Panics if `rustc_path` does not lead to a rustc repo or the files could not be read pub fn run(rustc_path: Option<&str>) { // we can unwrap here because the arg is required by clap - let rustc_path = PathBuf::from(rustc_path.unwrap()); + let rustc_path = PathBuf::from(rustc_path.unwrap()) + .canonicalize() + .expect("failed to get the absolute repo path"); assert!(rustc_path.is_dir(), "path is not a directory"); let rustc_source_basedir = rustc_path.join("compiler"); assert!( diff --git a/src/tools/clippy/clippy_dev/src/serve.rs b/src/tools/clippy/clippy_dev/src/serve.rs index faa94859601e3..d13c27a1957d6 100644 --- a/src/tools/clippy/clippy_dev/src/serve.rs +++ b/src/tools/clippy/clippy_dev/src/serve.rs @@ -34,7 +34,7 @@ pub fn run(port: u16, lint: Option<&str>) -> ! { // Give some time for python to start thread::sleep(Duration::from_millis(500)); // Launch browser after first export.py has completed and http.server is up - let _ = opener::open(url); + let _result = opener::open(url); }); } thread::sleep(Duration::from_millis(1000)); diff --git a/src/tools/clippy/clippy_lints/src/cargo_common_metadata.rs b/src/tools/clippy/clippy_lints/src/cargo_common_metadata.rs index 0d294761af5ab..cc2869ab495c8 100644 --- a/src/tools/clippy/clippy_lints/src/cargo_common_metadata.rs +++ b/src/tools/clippy/clippy_lints/src/cargo_common_metadata.rs @@ -5,7 +5,7 @@ use std::path::PathBuf; use crate::utils::{run_lints, span_lint}; use rustc_hir::{hir_id::CRATE_HIR_ID, Crate}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::DUMMY_SP; declare_clippy_lint! { @@ -51,6 +51,21 @@ declare_clippy_lint! { "common metadata is defined in `Cargo.toml`" } +#[derive(Copy, Clone, Debug)] +pub struct CargoCommonMetadata { + ignore_publish: bool, +} + +impl CargoCommonMetadata { + pub fn new(ignore_publish: bool) -> Self { + Self { ignore_publish } + } +} + +impl_lint_pass!(CargoCommonMetadata => [ + CARGO_COMMON_METADATA +]); + fn missing_warning(cx: &LateContext<'_>, package: &cargo_metadata::Package, field: &str) { let message = format!("package `{}` is missing `{}` metadata", package.name, field); span_lint(cx, CARGO_COMMON_METADATA, DUMMY_SP, &message); @@ -69,8 +84,6 @@ fn is_empty_vec(value: &[String]) -> bool { value.iter().all(String::is_empty) } -declare_lint_pass!(CargoCommonMetadata => [CARGO_COMMON_METADATA]); - impl LateLintPass<'_> for CargoCommonMetadata { fn check_crate(&mut self, cx: &LateContext<'_>, _: &Crate<'_>) { if !run_lints(cx, &[CARGO_COMMON_METADATA], CRATE_HIR_ID) { @@ -80,32 +93,36 @@ impl LateLintPass<'_> for CargoCommonMetadata { let metadata = unwrap_cargo_metadata!(cx, CARGO_COMMON_METADATA, false); for package in metadata.packages { - if is_empty_vec(&package.authors) { - missing_warning(cx, &package, "package.authors"); - } - - if is_empty_str(&package.description) { - missing_warning(cx, &package, "package.description"); - } - - if is_empty_str(&package.license) && is_empty_path(&package.license_file) { - missing_warning(cx, &package, "either package.license or package.license_file"); - } - - if is_empty_str(&package.repository) { - missing_warning(cx, &package, "package.repository"); - } - - if is_empty_path(&package.readme) { - missing_warning(cx, &package, "package.readme"); - } - - if is_empty_vec(&package.keywords) { - missing_warning(cx, &package, "package.keywords"); - } - - if is_empty_vec(&package.categories) { - missing_warning(cx, &package, "package.categories"); + // only run the lint if publish is `None` (`publish = true` or skipped entirely) + // or if the vector isn't empty (`publish = ["something"]`) + if package.publish.as_ref().filter(|publish| publish.is_empty()).is_none() || self.ignore_publish { + if is_empty_vec(&package.authors) { + missing_warning(cx, &package, "package.authors"); + } + + if is_empty_str(&package.description) { + missing_warning(cx, &package, "package.description"); + } + + if is_empty_str(&package.license) && is_empty_path(&package.license_file) { + missing_warning(cx, &package, "either package.license or package.license_file"); + } + + if is_empty_str(&package.repository) { + missing_warning(cx, &package, "package.repository"); + } + + if is_empty_path(&package.readme) { + missing_warning(cx, &package, "package.readme"); + } + + if is_empty_vec(&package.keywords) { + missing_warning(cx, &package, "package.keywords"); + } + + if is_empty_vec(&package.categories) { + missing_warning(cx, &package, "package.categories"); + } } } } diff --git a/src/tools/clippy/clippy_lints/src/collapsible_match.rs b/src/tools/clippy/clippy_lints/src/collapsible_match.rs index b83aae0e5719c..67282cb790057 100644 --- a/src/tools/clippy/clippy_lints/src/collapsible_match.rs +++ b/src/tools/clippy/clippy_lints/src/collapsible_match.rs @@ -1,10 +1,10 @@ use crate::utils::visitors::LocalUsedVisitor; -use crate::utils::{span_lint_and_then, SpanlessEq}; +use crate::utils::{path_to_local, 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, UnOp}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::{DefIdTree, TyCtxt}; +use rustc_middle::ty::{DefIdTree, TyCtxt, TypeckResults}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::{MultiSpan, Span}; @@ -60,7 +60,7 @@ impl<'tcx> LateLintPass<'tcx> for CollapsibleMatch { } } -fn check_arm(arm: &Arm<'_>, wild_outer_arm: &Arm<'_>, cx: &LateContext<'_>) { +fn check_arm<'tcx>(arm: &Arm<'tcx>, wild_outer_arm: &Arm<'tcx>, cx: &LateContext<'tcx>) { if_chain! { let expr = strip_singleton_blocks(arm.body); if let ExprKind::Match(expr_in, arms_inner, _) = expr.kind; @@ -72,7 +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 { .. } - if let Some(binding_id) = addr_adjusted_binding(expr_in, cx); + if let Some(binding_id) = path_to_local(strip_ref_operators(expr_in, cx.typeck_results())); // 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) = @@ -84,14 +84,13 @@ 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 + let mut used_visitor = LocalUsedVisitor::new(cx, binding_id); if match arm.guard { None => true, - Some(Guard::If(expr) | Guard::IfLet(_, expr)) => { - !LocalUsedVisitor::new(binding_id).check_expr(expr) - } + Some(Guard::If(expr) | Guard::IfLet(_, expr)) => !used_visitor.check_expr(expr), }; // ...or anywhere in the inner match - if !arms_inner.iter().any(|arm| LocalUsedVisitor::new(binding_id).check_arm(arm)); + if !arms_inner.iter().any(|arm| used_visitor.check_arm(arm)); then { span_lint_and_then( cx, @@ -175,19 +174,15 @@ 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 { +/// Removes `AddrOf` operators (`&`) or deref operators (`*`), but only if a reference type is +/// dereferenced. An overloaded deref such as `Vec` to slice would not be removed. +fn strip_ref_operators<'hir>(mut expr: &'hir Expr<'hir>, typeck_results: &TypeckResults<'_>) -> &'hir Expr<'hir> { 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::Deref, e) if cx.typeck_results().expr_ty(e).is_ref() => expr = e, - _ => break None, + ExprKind::Unary(UnOp::Deref, e) if typeck_results.expr_ty(e).is_ref() => expr = e, + _ => break, } } + expr } diff --git a/src/tools/clippy/clippy_lints/src/disallowed_method.rs b/src/tools/clippy/clippy_lints/src/disallowed_method.rs index 581c3242e3745..56dc6d18a58f2 100644 --- a/src/tools/clippy/clippy_lints/src/disallowed_method.rs +++ b/src/tools/clippy/clippy_lints/src/disallowed_method.rs @@ -1,29 +1,47 @@ -use crate::utils::span_lint; +use crate::utils::{fn_def_id, span_lint}; use rustc_data_structures::fx::FxHashSet; -use rustc_hir::{Expr, ExprKind}; +use rustc_hir::Expr; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::Symbol; declare_clippy_lint! { - /// **What it does:** Lints for specific trait methods defined in clippy.toml + /// **What it does:** Denies the configured methods and functions in clippy.toml /// /// **Why is this bad?** Some methods are undesirable in certain contexts, - /// and it would be beneficial to lint for them as needed. + /// and it's beneficial to lint for them as needed. /// - /// **Known problems:** None. + /// **Known problems:** Currently, you must write each function as a + /// fully-qualified path. This lint doesn't support aliases or reexported + /// names; be aware that many types in `std` are actually reexports. + /// + /// For example, if you want to disallow `Duration::as_secs`, your clippy.toml + /// configuration would look like + /// `disallowed-methods = ["core::time::Duration::as_secs"]` and not + /// `disallowed-methods = ["std::time::Duration::as_secs"]` as you might expect. /// /// **Example:** /// + /// An example clippy.toml configuration: + /// ```toml + /// # clippy.toml + /// disallowed-methods = ["alloc::vec::Vec::leak", "std::time::Instant::now"] + /// ``` + /// /// ```rust,ignore - /// // example code where clippy issues a warning - /// foo.bad_method(); // Foo::bad_method is disallowed in the configuration + /// // Example code where clippy issues a warning + /// let xs = vec![1, 2, 3, 4]; + /// xs.leak(); // Vec::leak is disallowed in the config. + /// + /// let _now = Instant::now(); // Instant::now is disallowed in the config. /// ``` + /// /// Use instead: /// ```rust,ignore - /// // example code which does not raise clippy warning - /// goodStruct.bad_method(); // GoodStruct::bad_method is not disallowed + /// // Example code which does not raise clippy warning + /// let mut xs = Vec::new(); // Vec::new is _not_ disallowed in the config. + /// xs.push(123); // Vec::push is _not_ disallowed in the config. /// ``` pub DISALLOWED_METHOD, nursery, @@ -50,14 +68,12 @@ impl_lint_pass!(DisallowedMethod => [DISALLOWED_METHOD]); impl<'tcx> LateLintPass<'tcx> for DisallowedMethod { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if let ExprKind::MethodCall(_path, _, _args, _) = &expr.kind { - let def_id = cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap(); - - let method_call = cx.get_def_path(def_id); - if self.disallowed.contains(&method_call) { - let method = method_call - .iter() - .map(|s| s.to_ident_string()) + if let Some(def_id) = fn_def_id(cx, expr) { + let func_path = cx.get_def_path(def_id); + if self.disallowed.contains(&func_path) { + let func_path_string = func_path + .into_iter() + .map(Symbol::to_ident_string) .collect::>() .join("::"); @@ -65,7 +81,7 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedMethod { cx, DISALLOWED_METHOD, expr.span, - &format!("use of a disallowed method `{}`", method), + &format!("use of a disallowed method `{}`", func_path_string), ); } } diff --git a/src/tools/clippy/clippy_lints/src/eval_order_dependence.rs b/src/tools/clippy/clippy_lints/src/eval_order_dependence.rs index bc2b2904698c7..83cee11c3a859 100644 --- a/src/tools/clippy/clippy_lints/src/eval_order_dependence.rs +++ b/src/tools/clippy/clippy_lints/src/eval_order_dependence.rs @@ -1,7 +1,6 @@ -use crate::utils::{get_parent_expr, span_lint, span_lint_and_note}; -use if_chain::if_chain; +use crate::utils::{get_parent_expr, path_to_local, path_to_local_id, span_lint, span_lint_and_note}; use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; -use rustc_hir::{def, BinOpKind, Block, Expr, ExprKind, Guard, HirId, Local, Node, QPath, Stmt, StmtKind}; +use rustc_hir::{BinOpKind, Block, Expr, ExprKind, Guard, HirId, Local, Node, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::map::Map; use rustc_middle::ty; @@ -72,20 +71,14 @@ impl<'tcx> LateLintPass<'tcx> for EvalOrderDependence { // Find a write to a local variable. match expr.kind { ExprKind::Assign(ref lhs, ..) | ExprKind::AssignOp(_, ref lhs, _) => { - if let ExprKind::Path(ref qpath) = lhs.kind { - if let QPath::Resolved(_, ref path) = *qpath { - if path.segments.len() == 1 { - if let def::Res::Local(var) = cx.qpath_res(qpath, lhs.hir_id) { - let mut visitor = ReadVisitor { - cx, - var, - write_expr: expr, - last_expr: expr, - }; - check_for_unsequenced_reads(&mut visitor); - } - } - } + if let Some(var) = path_to_local(lhs) { + let mut visitor = ReadVisitor { + cx, + var, + write_expr: expr, + last_expr: expr, + }; + check_for_unsequenced_reads(&mut visitor); } }, _ => {}, @@ -304,27 +297,20 @@ impl<'a, 'tcx> Visitor<'tcx> for ReadVisitor<'a, 'tcx> { return; } - match expr.kind { - ExprKind::Path(ref qpath) => { - if_chain! { - if let QPath::Resolved(None, ref path) = *qpath; - if path.segments.len() == 1; - if let def::Res::Local(local_id) = self.cx.qpath_res(qpath, expr.hir_id); - if local_id == self.var; - // Check that this is a read, not a write. - if !is_in_assignment_position(self.cx, expr); - then { - span_lint_and_note( - self.cx, - EVAL_ORDER_DEPENDENCE, - expr.span, - "unsequenced read of a variable", - Some(self.write_expr.span), - "whether read occurs before this write depends on evaluation order" - ); - } - } + if path_to_local_id(expr, self.var) { + // Check that this is a read, not a write. + if !is_in_assignment_position(self.cx, expr) { + span_lint_and_note( + self.cx, + EVAL_ORDER_DEPENDENCE, + expr.span, + "unsequenced read of a variable", + Some(self.write_expr.span), + "whether read occurs before this write depends on evaluation order", + ); } + } + match expr.kind { // We're about to descend a closure. Since we don't know when (or // if) the closure will be evaluated, any reads in it might not // occur here (or ever). Like above, bail to avoid false positives. diff --git a/src/tools/clippy/clippy_lints/src/functions.rs b/src/tools/clippy/clippy_lints/src/functions.rs index 71a146cc29805..94200a1542084 100644 --- a/src/tools/clippy/clippy_lints/src/functions.rs +++ b/src/tools/clippy/clippy_lints/src/functions.rs @@ -1,7 +1,7 @@ use crate::utils::{ attr_by_name, attrs::is_proc_macro, is_must_use_ty, is_trait_impl_item, is_type_diagnostic_item, iter_input_pats, - last_path_segment, match_def_path, must_use_attr, return_ty, snippet, snippet_opt, span_lint, span_lint_and_help, - span_lint_and_then, trait_ref_of_method, type_is_unsafe_function, + last_path_segment, match_def_path, must_use_attr, path_to_local, return_ty, snippet, snippet_opt, span_lint, + span_lint_and_help, span_lint_and_then, trait_ref_of_method, type_is_unsafe_function, }; use if_chain::if_chain; use rustc_ast::ast::Attribute; @@ -9,7 +9,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::intravisit; -use rustc_hir::{def::Res, def_id::DefId}; +use rustc_hir::{def::Res, def_id::DefId, QPath}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::map::Map; use rustc_middle::lint::in_external_macro; @@ -658,16 +658,14 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for DerefVisitor<'a, 'tcx> { impl<'a, 'tcx> DerefVisitor<'a, 'tcx> { fn check_arg(&self, ptr: &hir::Expr<'_>) { - if let hir::ExprKind::Path(ref qpath) = ptr.kind { - if let Res::Local(id) = self.cx.qpath_res(qpath, ptr.hir_id) { - if self.ptrs.contains(&id) { - span_lint( - self.cx, - NOT_UNSAFE_PTR_ARG_DEREF, - ptr.span, - "this public function dereferences a raw pointer but is not marked `unsafe`", - ); - } + if let Some(id) = path_to_local(ptr) { + if self.ptrs.contains(&id) { + span_lint( + self.cx, + NOT_UNSAFE_PTR_ARG_DEREF, + ptr.span, + "this public function dereferences a raw pointer but is not marked `unsafe`", + ); } } } @@ -698,7 +696,7 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for StaticMutVisitor<'a, 'tcx> { arg.span, &mut tys, ) - && is_mutated_static(self.cx, arg) + && is_mutated_static(arg) { self.mutates_static = true; return; @@ -707,7 +705,7 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for StaticMutVisitor<'a, 'tcx> { } }, Assign(ref target, ..) | AssignOp(_, ref target, _) | AddrOf(_, hir::Mutability::Mut, ref target) => { - self.mutates_static |= is_mutated_static(self.cx, target) + self.mutates_static |= is_mutated_static(target) }, _ => {}, } @@ -718,12 +716,13 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for StaticMutVisitor<'a, 'tcx> { } } -fn is_mutated_static(cx: &LateContext<'_>, e: &hir::Expr<'_>) -> bool { +fn is_mutated_static(e: &hir::Expr<'_>) -> bool { use hir::ExprKind::{Field, Index, Path}; match e.kind { - Path(ref qpath) => !matches!(cx.qpath_res(qpath, e.hir_id), Res::Local(_)), - Field(ref inner, _) | Index(ref inner, _) => is_mutated_static(cx, inner), + Path(QPath::Resolved(_, path)) => !matches!(path.res, Res::Local(_)), + Path(_) => true, + Field(ref inner, _) | Index(ref inner, _) => is_mutated_static(inner), _ => false, } } diff --git a/src/tools/clippy/clippy_lints/src/let_if_seq.rs b/src/tools/clippy/clippy_lints/src/let_if_seq.rs index 5886c2360e362..5863eef8a26f8 100644 --- a/src/tools/clippy/clippy_lints/src/let_if_seq.rs +++ b/src/tools/clippy/clippy_lints/src/let_if_seq.rs @@ -1,8 +1,7 @@ -use crate::utils::{snippet, span_lint_and_then, visitors::LocalUsedVisitor}; +use crate::utils::{path_to_local_id, snippet, span_lint_and_then, visitors::LocalUsedVisitor}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_hir::def::Res; use rustc_hir::BindingAnnotation; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -64,10 +63,11 @@ impl<'tcx> LateLintPass<'tcx> for LetIfSeq { if let hir::PatKind::Binding(mode, canonical_id, ident, None) = local.pat.kind; if let hir::StmtKind::Expr(ref if_) = expr.kind; if let hir::ExprKind::If(ref cond, ref then, ref else_) = if_.kind; - if !LocalUsedVisitor::new(canonical_id).check_expr(cond); + let mut used_visitor = LocalUsedVisitor::new(cx, canonical_id); + if !used_visitor.check_expr(cond); if let hir::ExprKind::Block(ref then, _) = then.kind; if let Some(value) = check_assign(cx, canonical_id, &*then); - if !LocalUsedVisitor::new(canonical_id).check_expr(value); + if !used_visitor.check_expr(value); then { let span = stmt.span.to(if_.span); @@ -144,11 +144,9 @@ fn check_assign<'tcx>( if let Some(expr) = block.stmts.iter().last(); if let hir::StmtKind::Semi(ref expr) = expr.kind; if let hir::ExprKind::Assign(ref var, ref value, _) = expr.kind; - if let hir::ExprKind::Path(ref qpath) = var.kind; - if let Res::Local(local_id) = cx.qpath_res(qpath, var.hir_id); - if decl == local_id; + if path_to_local_id(var, decl); then { - let mut v = LocalUsedVisitor::new(decl); + let mut v = LocalUsedVisitor::new(cx, decl); if block.stmts.iter().take(block.stmts.len()-1).any(|stmt| v.check_stmt(stmt)) { return None; diff --git a/src/tools/clippy/clippy_lints/src/let_underscore.rs b/src/tools/clippy/clippy_lints/src/let_underscore.rs index 6a5a77f8690a9..7e96dfcc7da0f 100644 --- a/src/tools/clippy/clippy_lints/src/let_underscore.rs +++ b/src/tools/clippy/clippy_lints/src/let_underscore.rs @@ -5,7 +5,7 @@ use rustc_middle::lint::in_external_macro; use rustc_middle::ty::subst::GenericArgKind; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use crate::utils::{implements_trait, is_must_use_func_call, is_must_use_ty, match_type, paths, span_lint_and_help}; +use crate::utils::{is_must_use_func_call, is_must_use_ty, match_type, paths, span_lint_and_help}; declare_clippy_lint! { /// **What it does:** Checks for `let _ = ` @@ -125,15 +125,6 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false, }); - let implements_drop = cx.tcx.lang_items().drop_trait().map_or(false, |drop_trait| - init_ty.walk().any(|inner| match inner.unpack() { - GenericArgKind::Type(inner_ty) => { - implements_trait(cx, inner_ty, drop_trait, &[]) - }, - - GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false, - }) - ); if contains_sync_guard { span_lint_and_help( cx, @@ -144,7 +135,7 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { "consider using an underscore-prefixed named \ binding or dropping explicitly with `std::mem::drop`" ) - } else if implements_drop { + } else if init_ty.needs_drop(cx.tcx, cx.param_env) { span_lint_and_help( cx, LET_UNDERSCORE_DROP, diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index 5a40c00bd673a..d96911fac1a07 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -310,6 +310,7 @@ mod regex; mod repeat_once; mod returns; mod self_assignment; +mod semicolon_if_nothing_returned; mod serde_api; mod shadow; mod single_component_path_imports; @@ -687,6 +688,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &loops::FOR_KV_MAP, &loops::FOR_LOOPS_OVER_FALLIBLES, &loops::ITER_NEXT_LOOP, + &loops::MANUAL_FLATTEN, &loops::MANUAL_MEMCPY, &loops::MUT_RANGE_BOUND, &loops::NEEDLESS_COLLECT, @@ -732,6 +734,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &mem_replace::MEM_REPLACE_WITH_DEFAULT, &mem_replace::MEM_REPLACE_WITH_UNINIT, &methods::BIND_INSTEAD_OF_MAP, + &methods::BYTES_NTH, &methods::CHARS_LAST_CMP, &methods::CHARS_NEXT_CMP, &methods::CLONE_DOUBLE_REF, @@ -741,6 +744,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &methods::EXPECT_USED, &methods::FILETYPE_IS_FILE, &methods::FILTER_MAP, + &methods::FILTER_MAP_IDENTITY, &methods::FILTER_MAP_NEXT, &methods::FILTER_NEXT, &methods::FLAT_MAP_IDENTITY, @@ -875,6 +879,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &returns::LET_AND_RETURN, &returns::NEEDLESS_RETURN, &self_assignment::SELF_ASSIGNMENT, + &semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED, &serde_api::SERDE_API_MISUSE, &shadow::SHADOW_REUSE, &shadow::SHADOW_SAME, @@ -1179,7 +1184,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_early_pass(|| box redundant_else::RedundantElse); store.register_late_pass(|| box create_dir::CreateDir); store.register_early_pass(|| box needless_arbitrary_self_type::NeedlessArbitrarySelfType); - store.register_late_pass(|| box cargo_common_metadata::CargoCommonMetadata); + let cargo_ignore_publish = conf.cargo_ignore_publish; + store.register_late_pass(move || box cargo_common_metadata::CargoCommonMetadata::new(cargo_ignore_publish)); store.register_late_pass(|| box multiple_crate_versions::MultipleCrateVersions); store.register_late_pass(|| box wildcard_dependencies::WildcardDependencies); let literal_representation_lint_fraction_readability = conf.unreadable_literal_lint_fractions; @@ -1236,6 +1242,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box manual_unwrap_or::ManualUnwrapOr); store.register_late_pass(|| box manual_ok_or::ManualOkOr); store.register_late_pass(|| box float_equality_without_abs::FloatEqualityWithoutAbs); + store.register_late_pass(|| box semicolon_if_nothing_returned::SemicolonIfNothingReturned); store.register_late_pass(|| box async_yields_async::AsyncYieldsAsync); let disallowed_methods = conf.disallowed_methods.iter().cloned().collect::>(); store.register_late_pass(move || box disallowed_method::DisallowedMethod::new(&disallowed_methods)); @@ -1290,6 +1297,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&panic_unimplemented::UNIMPLEMENTED), LintId::of(&panic_unimplemented::UNREACHABLE), LintId::of(&pattern_type_mismatch::PATTERN_TYPE_MISMATCH), + LintId::of(&semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED), LintId::of(&shadow::SHADOW_REUSE), LintId::of(&shadow::SHADOW_SAME), LintId::of(&strings::STRING_ADD), @@ -1491,6 +1499,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&loops::FOR_KV_MAP), LintId::of(&loops::FOR_LOOPS_OVER_FALLIBLES), LintId::of(&loops::ITER_NEXT_LOOP), + LintId::of(&loops::MANUAL_FLATTEN), LintId::of(&loops::MANUAL_MEMCPY), LintId::of(&loops::MUT_RANGE_BOUND), LintId::of(&loops::NEEDLESS_COLLECT), @@ -1524,11 +1533,13 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&mem_replace::MEM_REPLACE_WITH_DEFAULT), LintId::of(&mem_replace::MEM_REPLACE_WITH_UNINIT), LintId::of(&methods::BIND_INSTEAD_OF_MAP), + LintId::of(&methods::BYTES_NTH), LintId::of(&methods::CHARS_LAST_CMP), LintId::of(&methods::CHARS_NEXT_CMP), LintId::of(&methods::CLONE_DOUBLE_REF), LintId::of(&methods::CLONE_ON_COPY), LintId::of(&methods::EXPECT_FUN_CALL), + LintId::of(&methods::FILTER_MAP_IDENTITY), LintId::of(&methods::FILTER_NEXT), LintId::of(&methods::FLAT_MAP_IDENTITY), LintId::of(&methods::FROM_ITER_INSTEAD_OF_COLLECT), @@ -1620,7 +1631,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&reference::DEREF_ADDROF), LintId::of(&reference::REF_IN_DEREF), LintId::of(®ex::INVALID_REGEX), - LintId::of(®ex::TRIVIAL_REGEX), LintId::of(&repeat_once::REPEAT_ONCE), LintId::of(&returns::LET_AND_RETURN), LintId::of(&returns::NEEDLESS_RETURN), @@ -1741,6 +1751,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&matches::SINGLE_MATCH), LintId::of(&mem_replace::MEM_REPLACE_OPTION_WITH_NONE), LintId::of(&mem_replace::MEM_REPLACE_WITH_DEFAULT), + LintId::of(&methods::BYTES_NTH), LintId::of(&methods::CHARS_LAST_CMP), LintId::of(&methods::CHARS_NEXT_CMP), LintId::of(&methods::FROM_ITER_INSTEAD_OF_COLLECT), @@ -1783,7 +1794,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&ranges::MANUAL_RANGE_CONTAINS), LintId::of(&redundant_field_names::REDUNDANT_FIELD_NAMES), LintId::of(&redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES), - LintId::of(®ex::TRIVIAL_REGEX), LintId::of(&returns::LET_AND_RETURN), LintId::of(&returns::NEEDLESS_RETURN), LintId::of(&single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS), @@ -1822,6 +1832,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&lifetimes::EXTRA_UNUSED_LIFETIMES), LintId::of(&lifetimes::NEEDLESS_LIFETIMES), LintId::of(&loops::EXPLICIT_COUNTER_LOOP), + LintId::of(&loops::MANUAL_FLATTEN), LintId::of(&loops::MUT_RANGE_BOUND), LintId::of(&loops::SINGLE_ELEMENT_LOOP), LintId::of(&loops::WHILE_LET_LOOP), @@ -1835,6 +1846,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&matches::WILDCARD_IN_OR_PATTERNS), LintId::of(&methods::BIND_INSTEAD_OF_MAP), LintId::of(&methods::CLONE_ON_COPY), + LintId::of(&methods::FILTER_MAP_IDENTITY), LintId::of(&methods::FILTER_NEXT), LintId::of(&methods::FLAT_MAP_IDENTITY), LintId::of(&methods::INSPECT_FOR_EACH), @@ -2011,6 +2023,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&needless_borrow::NEEDLESS_BORROW), LintId::of(&path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE), LintId::of(&redundant_pub_crate::REDUNDANT_PUB_CRATE), + LintId::of(®ex::TRIVIAL_REGEX), LintId::of(&strings::STRING_LIT_AS_BYTES), LintId::of(&transmute::USELESS_TRANSMUTE), LintId::of(&use_self::USE_SELF), diff --git a/src/tools/clippy/clippy_lints/src/loops.rs b/src/tools/clippy/clippy_lints/src/loops.rs index 5211ca7da323a..eb185377e2094 100644 --- a/src/tools/clippy/clippy_lints/src/loops.rs +++ b/src/tools/clippy/clippy_lints/src/loops.rs @@ -1,14 +1,13 @@ use crate::consts::constant; -use crate::utils::paths; use crate::utils::sugg::Sugg; -use crate::utils::usage::{is_unused, mutated_variables}; +use crate::utils::usage::mutated_variables; use crate::utils::visitors::LocalUsedVisitor; use crate::utils::{ contains_name, get_enclosing_block, get_parent_expr, get_trait_def_id, has_iter_method, higher, implements_trait, - indent_of, is_in_panic_handler, is_integer_const, is_no_std_crate, is_refutable, is_type_diagnostic_item, - last_path_segment, match_trait_method, match_type, match_var, multispan_sugg, single_segment_path, snippet, - snippet_with_applicability, snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_sugg, - span_lint_and_then, sugg, SpanlessEq, + indent_of, is_in_panic_handler, is_integer_const, is_no_std_crate, is_ok_ctor, is_refutable, is_some_ctor, + is_type_diagnostic_item, last_path_segment, match_trait_method, match_type, multispan_sugg, path_to_local, + path_to_local_id, paths, single_segment_path, snippet, snippet_with_applicability, snippet_with_macro_callsite, + span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then, sugg, SpanlessEq, }; use if_chain::if_chain; use rustc_ast::ast; @@ -494,8 +493,40 @@ declare_clippy_lint! { "there is no reason to have a single element loop" } +declare_clippy_lint! { + /// **What it does:** Check for unnecessary `if let` usage in a for loop + /// where only the `Some` or `Ok` variant of the iterator element is used. + /// + /// **Why is this bad?** It is verbose and can be simplified + /// by first calling the `flatten` method on the `Iterator`. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust + /// let x = vec![Some(1), Some(2), Some(3)]; + /// for n in x { + /// if let Some(n) = n { + /// println!("{}", n); + /// } + /// } + /// ``` + /// Use instead: + /// ```rust + /// let x = vec![Some(1), Some(2), Some(3)]; + /// for n in x.into_iter().flatten() { + /// println!("{}", n); + /// } + /// ``` + pub MANUAL_FLATTEN, + complexity, + "for loops over `Option`s or `Result`s with a single expression can be simplified" +} + declare_lint_pass!(Loops => [ MANUAL_MEMCPY, + MANUAL_FLATTEN, NEEDLESS_RANGE_LOOP, EXPLICIT_ITER_LOOP, EXPLICIT_INTO_ITER_LOOP, @@ -517,14 +548,14 @@ declare_lint_pass!(Loops => [ impl<'tcx> LateLintPass<'tcx> for Loops { #[allow(clippy::too_many_lines)] fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if let Some((pat, arg, body)) = higher::for_loop(expr) { + if let Some((pat, arg, body, span)) = higher::for_loop(expr) { // we don't want to check expanded macros // this check is not at the top of the function // since higher::for_loop expressions are marked as expansions if body.span.from_expansion() { return; } - check_for_loop(cx, pat, arg, body, expr); + check_for_loop(cx, pat, arg, body, expr, span); } // we don't want to check expanded macros @@ -707,7 +738,7 @@ fn combine_branches(b1: NeverLoopResult, b2: NeverLoopResult) -> NeverLoopResult fn never_loop_block(block: &Block<'_>, main_loop_id: HirId) -> NeverLoopResult { let stmts = block.stmts.iter().map(stmt_to_expr); let expr = once(block.expr.as_deref()); - let mut iter = stmts.chain(expr).filter_map(|e| e); + let mut iter = stmts.chain(expr).flatten(); never_loop_expr_seq(&mut iter, main_loop_id) } @@ -819,6 +850,7 @@ fn check_for_loop<'tcx>( arg: &'tcx Expr<'_>, body: &'tcx Expr<'_>, expr: &'tcx Expr<'_>, + span: Span, ) { let is_manual_memcpy_triggered = detect_manual_memcpy(cx, pat, arg, body, expr); if !is_manual_memcpy_triggered { @@ -830,6 +862,7 @@ fn check_for_loop<'tcx>( check_for_mut_range_bound(cx, arg, body); check_for_single_element_loop(cx, pat, arg, body, expr); detect_same_item_push(cx, pat, arg, body, expr); + check_manual_flatten(cx, pat, arg, body, span); } // this function assumes the given expression is a `for` loop. @@ -843,21 +876,6 @@ fn get_span_of_entire_for_loop(expr: &Expr<'_>) -> Span { } } -fn same_var<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, var: HirId) -> bool { - if_chain! { - if let ExprKind::Path(qpath) = &expr.kind; - if let QPath::Resolved(None, path) = qpath; - if path.segments.len() == 1; - if let Res::Local(local_id) = cx.qpath_res(qpath, expr.hir_id); - then { - // our variable! - local_id == var - } else { - false - } - } -} - /// a wrapper of `Sugg`. Besides what `Sugg` do, this removes unnecessary `0`; /// and also, it avoids subtracting a variable from the same one by replacing it with `0`. /// it exists for the convenience of the overloaded operators while normal functions can do the @@ -1010,14 +1028,9 @@ fn get_details_from_idx<'tcx>( idx: &Expr<'_>, starts: &[Start<'tcx>], ) -> Option<(StartKind<'tcx>, Offset)> { - fn get_start<'tcx>(cx: &LateContext<'tcx>, e: &Expr<'_>, starts: &[Start<'tcx>]) -> Option> { - starts.iter().find_map(|start| { - if same_var(cx, e, start.id) { - Some(start.kind) - } else { - None - } - }) + fn get_start<'tcx>(e: &Expr<'_>, starts: &[Start<'tcx>]) -> Option> { + let id = path_to_local(e)?; + starts.iter().find(|start| start.id == id).map(|start| start.kind) } fn get_offset<'tcx>(cx: &LateContext<'tcx>, e: &Expr<'_>, starts: &[Start<'tcx>]) -> Option> { @@ -1026,7 +1039,7 @@ fn get_details_from_idx<'tcx>( ast::LitKind::Int(x, _ty) => Some(Sugg::NonParen(x.to_string().into())), _ => None, }, - ExprKind::Path(..) if get_start(cx, e, starts).is_none() => Some(Sugg::hir(cx, e, "???")), + ExprKind::Path(..) if get_start(e, starts).is_none() => Some(Sugg::hir(cx, e, "???")), _ => None, } } @@ -1034,18 +1047,18 @@ fn get_details_from_idx<'tcx>( match idx.kind { ExprKind::Binary(op, lhs, rhs) => match op.node { BinOpKind::Add => { - let offset_opt = get_start(cx, lhs, starts) + let offset_opt = get_start(lhs, starts) .and_then(|s| get_offset(cx, rhs, starts).map(|o| (s, o))) - .or_else(|| get_start(cx, rhs, starts).and_then(|s| get_offset(cx, lhs, starts).map(|o| (s, o)))); + .or_else(|| get_start(rhs, starts).and_then(|s| get_offset(cx, lhs, starts).map(|o| (s, o)))); offset_opt.map(|(s, o)| (s, Offset::positive(o))) }, BinOpKind::Sub => { - get_start(cx, lhs, starts).and_then(|s| get_offset(cx, rhs, starts).map(|o| (s, Offset::negative(o)))) + get_start(lhs, starts).and_then(|s| get_offset(cx, rhs, starts).map(|o| (s, Offset::negative(o)))) }, _ => None, }, - ExprKind::Path(..) => get_start(cx, idx, starts).map(|s| (s, Offset::empty())), + ExprKind::Path(..) => get_start(idx, starts).map(|s| (s, Offset::empty())), _ => None, } } @@ -1062,11 +1075,10 @@ fn get_assignment<'tcx>(e: &'tcx Expr<'tcx>) -> Option<(&'tcx Expr<'tcx>, &'tcx /// The returned iterator yields `None` if no assignment expressions are there, /// filtering out the increments of the given whitelisted loop counters; /// because its job is to make sure there's nothing other than assignments and the increments. -fn get_assignments<'a: 'c, 'tcx: 'c, 'c>( - cx: &'a LateContext<'tcx>, +fn get_assignments<'a, 'tcx>( Block { stmts, expr, .. }: &'tcx Block<'tcx>, - loop_counters: &'c [Start<'tcx>], -) -> impl Iterator, &'tcx Expr<'tcx>)>> + 'c { + loop_counters: &'a [Start<'tcx>], +) -> impl Iterator, &'tcx Expr<'tcx>)>> + 'a { // As the `filter` and `map` below do different things, I think putting together // just increases complexity. (cc #3188 and #4193) stmts @@ -1078,12 +1090,14 @@ fn get_assignments<'a: 'c, 'tcx: 'c, 'c>( .chain((*expr).into_iter()) .filter(move |e| { if let ExprKind::AssignOp(_, place, _) = e.kind { - !loop_counters - .iter() - // skip the first item which should be `StartKind::Range` - // this makes it possible to use the slice with `StartKind::Range` in the same iterator loop. - .skip(1) - .any(|counter| same_var(cx, place, counter.id)) + path_to_local(place).map_or(false, |id| { + !loop_counters + .iter() + // skip the first item which should be `StartKind::Range` + // this makes it possible to use the slice with `StartKind::Range` in the same iterator loop. + .skip(1) + .any(|counter| counter.id == id) + }) } else { true } @@ -1140,7 +1154,7 @@ fn build_manual_memcpy_suggestion<'tcx>( if method.ident.name == sym!(len); if len_args.len() == 1; if let Some(arg) = len_args.get(0); - if var_def_id(cx, arg) == var_def_id(cx, base); + if path_to_local(arg) == path_to_local(base); then { if sugg.as_str() == end_str { sugg::EMPTY.into() @@ -1245,7 +1259,7 @@ fn detect_manual_memcpy<'tcx>( if let Some(loop_counters) = get_loop_counters(cx, block, expr) { starts.extend(loop_counters); } - iter_a = Some(get_assignments(cx, block, &starts)); + iter_a = Some(get_assignments(block, &starts)); } else { iter_b = Some(get_assignment(body)); } @@ -1267,7 +1281,7 @@ fn detect_manual_memcpy<'tcx>( if let Some((start_right, offset_right)) = get_details_from_idx(cx, &idx_right, &starts); // Source and destination must be different - if var_def_id(cx, base_left) != var_def_id(cx, base_right); + if path_to_local(base_left) != path_to_local(base_right); then { Some((IndexExpr { base: base_left, idx: start_left, idx_offset: offset_left }, IndexExpr { base: base_right, idx: start_right, idx_offset: offset_right })) @@ -1879,8 +1893,8 @@ fn check_for_loop_over_map_kv<'tcx>( let arg_span = arg.span; let (new_pat_span, kind, ty, mutbl) = match *cx.typeck_results().expr_ty(arg).kind() { ty::Ref(_, ty, mutbl) => match (&pat[0].kind, &pat[1].kind) { - (key, _) if pat_is_wild(key, body) => (pat[1].span, "value", ty, mutbl), - (_, value) if pat_is_wild(value, body) => (pat[0].span, "key", ty, Mutability::Not), + (key, _) if pat_is_wild(cx, key, body) => (pat[1].span, "value", ty, mutbl), + (_, value) if pat_is_wild(cx, value, body) => (pat[0].span, "key", ty, Mutability::Not), _ => return, }, _ => return, @@ -1953,6 +1967,77 @@ fn check_for_single_element_loop<'tcx>( } } +/// Check for unnecessary `if let` usage in a for loop where only the `Some` or `Ok` variant of the +/// iterator element is used. +fn check_manual_flatten<'tcx>( + cx: &LateContext<'tcx>, + pat: &'tcx Pat<'_>, + arg: &'tcx Expr<'_>, + body: &'tcx Expr<'_>, + span: Span, +) { + if let ExprKind::Block(ref block, _) = body.kind { + // Ensure the `if let` statement is the only expression or statement in the for-loop + let inner_expr = if block.stmts.len() == 1 && block.expr.is_none() { + let match_stmt = &block.stmts[0]; + if let StmtKind::Semi(inner_expr) = match_stmt.kind { + Some(inner_expr) + } else { + None + } + } else if block.stmts.is_empty() { + block.expr + } else { + None + }; + + if_chain! { + if let Some(inner_expr) = inner_expr; + if let ExprKind::Match( + ref match_expr, ref match_arms, MatchSource::IfLetDesugar{ contains_else_clause: false } + ) = inner_expr.kind; + // Ensure match_expr in `if let` statement is the same as the pat from the for-loop + if let PatKind::Binding(_, pat_hir_id, _, _) = pat.kind; + if path_to_local_id(match_expr, pat_hir_id); + // Ensure the `if let` statement is for the `Some` variant of `Option` or the `Ok` variant of `Result` + if let PatKind::TupleStruct(QPath::Resolved(None, path), _, _) = match_arms[0].pat.kind; + let some_ctor = is_some_ctor(cx, path.res); + let ok_ctor = is_ok_ctor(cx, path.res); + if some_ctor || ok_ctor; + let if_let_type = if some_ctor { "Some" } else { "Ok" }; + + then { + // Prepare the error message + let msg = format!("unnecessary `if let` since only the `{}` variant of the iterator element is used", if_let_type); + + // Prepare the help message + let mut applicability = Applicability::MaybeIncorrect; + let arg_snippet = make_iterator_snippet(cx, arg, &mut applicability); + + span_lint_and_then( + cx, + MANUAL_FLATTEN, + span, + &msg, + |diag| { + let sugg = format!("{}.flatten()", arg_snippet); + diag.span_suggestion( + arg.span, + "try", + sugg, + Applicability::MaybeIncorrect, + ); + diag.span_help( + inner_expr.span, + "...and remove the `if let` statement in the for loop", + ); + } + ); + } + } + } +} + struct MutatePairDelegate<'a, 'tcx> { cx: &'a LateContext<'tcx>, hir_id_low: Option, @@ -2024,20 +2109,11 @@ fn mut_warn_with_span(cx: &LateContext<'_>, span: Option) { fn check_for_mutability(cx: &LateContext<'_>, bound: &Expr<'_>) -> Option { if_chain! { - if let ExprKind::Path(ref qpath) = bound.kind; - if let QPath::Resolved(None, _) = *qpath; + if let Some(hir_id) = path_to_local(bound); + if let Node::Binding(pat) = cx.tcx.hir().get(hir_id); + if let PatKind::Binding(BindingAnnotation::Mutable, ..) = pat.kind; then { - let res = cx.qpath_res(qpath, bound.hir_id); - if let Res::Local(hir_id) = res { - let node_str = cx.tcx.hir().get(hir_id); - if_chain! { - if let Node::Binding(pat) = node_str; - if let PatKind::Binding(BindingAnnotation::Mutable, ..) = pat.kind; - then { - return Some(hir_id); - } - } - } + return Some(hir_id); } } None @@ -2069,10 +2145,12 @@ fn check_for_mutation<'tcx>( } /// Returns `true` if the pattern is a `PatWild` or an ident prefixed with `_`. -fn pat_is_wild<'tcx>(pat: &'tcx PatKind<'_>, body: &'tcx Expr<'_>) -> bool { +fn pat_is_wild<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx PatKind<'_>, body: &'tcx Expr<'_>) -> bool { match *pat { PatKind::Wild => true, - PatKind::Binding(.., ident, None) if ident.as_str().starts_with('_') => is_unused(&ident, body), + PatKind::Binding(_, id, ident, None) if ident.as_str().starts_with('_') => { + !LocalUsedVisitor::new(cx, id).check_expr(body) + }, _ => false, } } @@ -2108,9 +2186,9 @@ impl<'a, 'tcx> VarVisitor<'a, 'tcx> { if let QPath::Resolved(None, ref seqvar) = *seqpath; if seqvar.segments.len() == 1; then { - let index_used_directly = same_var(self.cx, idx, self.var); + let index_used_directly = path_to_local_id(idx, self.var); let indexed_indirectly = { - let mut used_visitor = LocalUsedVisitor::new(self.var); + let mut used_visitor = LocalUsedVisitor::new(self.cx, self.var); walk_expr(&mut used_visitor, idx); used_visitor.used }; @@ -2179,17 +2257,14 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> { if_chain! { // directly using a variable - if let ExprKind::Path(ref qpath) = expr.kind; - if let QPath::Resolved(None, ref path) = *qpath; - if path.segments.len() == 1; + if let ExprKind::Path(QPath::Resolved(None, path)) = expr.kind; + if let Res::Local(local_id) = path.res; then { - if let Res::Local(local_id) = self.cx.qpath_res(qpath, expr.hir_id) { - if local_id == self.var { - self.nonindex = true; - } else { - // not the correct variable, but still a variable - self.referenced.insert(path.segments[0].ident.name); - } + if local_id == self.var { + self.nonindex = true; + } else { + // not the correct variable, but still a variable + self.referenced.insert(path.segments[0].ident.name); } } } @@ -2247,7 +2322,7 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> { } fn is_used_inside<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, container: &'tcx Expr<'_>) -> bool { - let def_id = match var_def_id(cx, expr) { + let def_id = match path_to_local(expr) { Some(id) => id, None => return false, }; @@ -2260,12 +2335,11 @@ fn is_used_inside<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, container: } fn is_iterator_used_after_while_let<'tcx>(cx: &LateContext<'tcx>, iter_expr: &'tcx Expr<'_>) -> bool { - let def_id = match var_def_id(cx, iter_expr) { + let def_id = match path_to_local(iter_expr) { Some(id) => id, None => return false, }; let mut visitor = VarUsedAfterLoopVisitor { - cx, def_id, iter_expr_id: iter_expr.hir_id, past_while_let: false, @@ -2277,20 +2351,19 @@ fn is_iterator_used_after_while_let<'tcx>(cx: &LateContext<'tcx>, iter_expr: &'t visitor.var_used_after_while_let } -struct VarUsedAfterLoopVisitor<'a, 'tcx> { - cx: &'a LateContext<'tcx>, +struct VarUsedAfterLoopVisitor { def_id: HirId, iter_expr_id: HirId, past_while_let: bool, var_used_after_while_let: bool, } -impl<'a, 'tcx> Visitor<'tcx> for VarUsedAfterLoopVisitor<'a, 'tcx> { +impl<'tcx> Visitor<'tcx> for VarUsedAfterLoopVisitor { type Map = Map<'tcx>; fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { if self.past_while_let { - if Some(self.def_id) == var_def_id(self.cx, expr) { + if path_to_local_id(expr, self.def_id) { self.var_used_after_while_let = true; } } else if self.iter_expr_id == expr.hir_id { @@ -2412,7 +2485,7 @@ impl<'a, 'tcx> Visitor<'tcx> for IncrementVisitor<'a, 'tcx> { } // If node is a variable - if let Some(def_id) = var_def_id(self.cx, expr) { + if let Some(def_id) = path_to_local(expr) { if let Some(parent) = get_parent_expr(self.cx, expr) { let state = self.states.entry(def_id).or_insert(IncrementVisitorVarState::Initial); if *state == IncrementVisitorVarState::IncrOnce { @@ -2539,7 +2612,7 @@ impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> { } // If node is the desired variable, see how it's used - if var_def_id(self.cx, expr) == Some(self.var_id) { + if path_to_local_id(expr, self.var_id) { if self.past_loop { self.state = InitializeVisitorState::DontWarn; return; @@ -2586,16 +2659,6 @@ impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> { } } -fn var_def_id(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { - if let ExprKind::Path(ref qpath) = expr.kind { - let path_res = cx.qpath_res(qpath, expr.hir_id); - if let Res::Local(hir_id) = path_res { - return Some(hir_id); - } - } - None -} - fn is_loop(expr: &Expr<'_>) -> bool { matches!(expr.kind, ExprKind::Loop(..)) } @@ -2618,8 +2681,8 @@ fn is_nested(cx: &LateContext<'_>, match_expr: &Expr<'_>, iter_expr: &Expr<'_>) fn is_loop_nested(cx: &LateContext<'_>, loop_expr: &Expr<'_>, iter_expr: &Expr<'_>) -> bool { let mut id = loop_expr.hir_id; - let iter_name = if let Some(name) = path_name(iter_expr) { - name + let iter_id = if let Some(id) = path_to_local(iter_expr) { + id } else { return true; }; @@ -2637,7 +2700,7 @@ fn is_loop_nested(cx: &LateContext<'_>, loop_expr: &Expr<'_>, iter_expr: &Expr<' Some(Node::Block(block)) => { let mut block_visitor = LoopNestVisitor { hir_id: id, - iterator: iter_name, + iterator: iter_id, nesting: Unknown, }; walk_block(&mut block_visitor, block); @@ -2665,7 +2728,7 @@ use self::Nesting::{LookFurther, RuledOut, Unknown}; struct LoopNestVisitor { hir_id: HirId, - iterator: Symbol, + iterator: HirId, nesting: Nesting, } @@ -2690,7 +2753,7 @@ impl<'tcx> Visitor<'tcx> for LoopNestVisitor { } match expr.kind { ExprKind::Assign(ref path, _, _) | ExprKind::AssignOp(_, ref path, _) => { - if match_var(path, self.iterator) { + if path_to_local_id(path, self.iterator) { self.nesting = RuledOut; } }, @@ -2702,8 +2765,8 @@ impl<'tcx> Visitor<'tcx> for LoopNestVisitor { if self.nesting != Unknown { return; } - if let PatKind::Binding(.., span_name, _) = pat.kind { - if self.iterator == span_name.name { + if let PatKind::Binding(_, id, ..) = pat.kind { + if id == self.iterator { self.nesting = RuledOut; return; } @@ -2716,16 +2779,6 @@ impl<'tcx> Visitor<'tcx> for LoopNestVisitor { } } -fn path_name(e: &Expr<'_>) -> Option { - if let ExprKind::Path(QPath::Resolved(_, ref path)) = e.kind { - let segments = &path.segments; - if segments.len() == 1 { - return Some(segments[0].ident.name); - } - }; - None -} - fn check_infinite_loop<'tcx>(cx: &LateContext<'tcx>, cond: &'tcx Expr<'_>, expr: &'tcx Expr<'_>) { if constant(cx, cx.typeck_results(), cond).is_some() { // A pure constant condition (e.g., `while false`) is not linted. @@ -3087,7 +3140,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UsedCountVisitor<'a, 'tcx> { type Map = Map<'tcx>; fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { - if same_var(self.cx, expr, self.id) { + if path_to_local_id(expr, self.id) { self.count += 1; } else { walk_expr(self, expr); diff --git a/src/tools/clippy/clippy_lints/src/macro_use.rs b/src/tools/clippy/clippy_lints/src/macro_use.rs index bb52888883af5..40f04bd677d52 100644 --- a/src/tools/clippy/clippy_lints/src/macro_use.rs +++ b/src/tools/clippy/clippy_lints/src/macro_use.rs @@ -160,7 +160,7 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports { let found_idx = self.mac_refs.iter().position(|mac| import.ends_with(&mac.name)); if let Some(idx) = found_idx { - let _ = self.mac_refs.remove(idx); + self.mac_refs.remove(idx); let seg = import.split("::").collect::>(); match seg.as_slice() { diff --git a/src/tools/clippy/clippy_lints/src/manual_ok_or.rs b/src/tools/clippy/clippy_lints/src/manual_ok_or.rs index 8c77e155b70ce..efb05b8ffdf4f 100644 --- a/src/tools/clippy/clippy_lints/src/manual_ok_or.rs +++ b/src/tools/clippy/clippy_lints/src/manual_ok_or.rs @@ -1,9 +1,10 @@ use crate::utils::{ - indent_of, is_type_diagnostic_item, match_qpath, paths, reindent_multiline, snippet_opt, span_lint_and_sugg, + indent_of, is_type_diagnostic_item, match_qpath, path_to_local_id, paths, reindent_multiline, snippet_opt, + span_lint_and_sugg, }; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::{def, Expr, ExprKind, PatKind, QPath}; +use rustc_hir::{Expr, ExprKind, PatKind}; use rustc_lint::LintContext; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; @@ -90,8 +91,6 @@ fn is_ok_wrapping(cx: &LateContext<'_>, map_expr: &Expr<'_>) -> bool { if let PatKind::Binding(_, param_id, ..) = body.params[0].pat.kind; if let ExprKind::Call(Expr { kind: ExprKind::Path(ok_path), .. }, &[ref ok_arg]) = body.value.kind; if match_qpath(ok_path, &paths::RESULT_OK); - if let ExprKind::Path(QPath::Resolved(_, ok_arg_path)) = ok_arg.kind; - if let def::Res::Local(ok_arg_path_id) = ok_arg_path.res; - then { param_id == ok_arg_path_id } else { false } + then { path_to_local_id(ok_arg, param_id) } else { false } } } diff --git a/src/tools/clippy/clippy_lints/src/manual_unwrap_or.rs b/src/tools/clippy/clippy_lints/src/manual_unwrap_or.rs index 9e2c6c7f231da..b452225b5db6c 100644 --- a/src/tools/clippy/clippy_lints/src/manual_unwrap_or.rs +++ b/src/tools/clippy/clippy_lints/src/manual_unwrap_or.rs @@ -1,9 +1,9 @@ use crate::consts::constant_simple; use crate::utils; -use crate::utils::sugg; +use crate::utils::{path_to_local_id, sugg}; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::{def, Arm, Expr, ExprKind, Pat, PatKind, QPath}; +use rustc_hir::{Arm, Expr, ExprKind, Pat, PatKind}; use rustc_lint::LintContext; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; @@ -83,9 +83,7 @@ fn lint_manual_unwrap_or<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { if utils::match_qpath(unwrap_qpath, &utils::paths::OPTION_SOME) || utils::match_qpath(unwrap_qpath, &utils::paths::RESULT_OK); if let PatKind::Binding(_, binding_hir_id, ..) = unwrap_pat.kind; - if let ExprKind::Path(QPath::Resolved(_, body_path)) = unwrap_arm.body.kind; - if let def::Res::Local(body_path_hir_id) = body_path.res; - if body_path_hir_id == binding_hir_id; + if path_to_local_id(unwrap_arm.body, binding_hir_id); if !utils::usage::contains_return_break_continue_macro(or_arm.body); then { Some(or_arm) diff --git a/src/tools/clippy/clippy_lints/src/matches.rs b/src/tools/clippy/clippy_lints/src/matches.rs index ba7b9bd04248d..e33001b16bcde 100644 --- a/src/tools/clippy/clippy_lints/src/matches.rs +++ b/src/tools/clippy/clippy_lints/src/matches.rs @@ -1,11 +1,12 @@ use crate::consts::{constant, miri_to_const, Constant}; use crate::utils::sugg::Sugg; -use crate::utils::usage::is_unused; +use crate::utils::visitors::LocalUsedVisitor; use crate::utils::{ - 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, + expr_block, 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, meets_msrv, multispan_sugg, path_to_local_id, 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, + strip_pat_refs, }; use crate::utils::{paths, search_same, SpanlessEq, SpanlessHash}; use if_chain::if_chain; @@ -616,9 +617,9 @@ impl<'tcx> LateLintPass<'tcx> for Matches { if let PatKind::TupleStruct( QPath::Resolved(None, ref variant_name), ref args, _) = arms[0].pat.kind; if args.len() == 1; - if let Some(arg) = get_arg_name(&args[0]); + if let PatKind::Binding(_, arg, ..) = strip_pat_refs(&args[0]).kind; let body = remove_blocks(&arms[0].body); - if match_var(body, arg); + if path_to_local_id(body, arg); then { let mut applicability = Applicability::MachineApplicable; @@ -910,7 +911,7 @@ fn check_overlapping_arms<'tcx>(cx: &LateContext<'tcx>, ex: &'tcx Expr<'_>, arms } } -fn check_wild_err_arm(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) { +fn check_wild_err_arm<'tcx>(cx: &LateContext<'tcx>, ex: &Expr<'tcx>, arms: &[Arm<'tcx>]) { let ex_ty = cx.typeck_results().expr_ty(ex).peel_refs(); if is_type_diagnostic_item(cx, ex_ty, sym::result_type) { for arm in arms { @@ -922,8 +923,10 @@ fn check_wild_err_arm(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) { if !matching_wild { // Looking for unused bindings (i.e.: `_e`) inner.iter().for_each(|pat| { - if let PatKind::Binding(.., ident, None) = &pat.kind { - if ident.as_str().starts_with('_') && is_unused(ident, arm.body) { + if let PatKind::Binding(_, id, ident, None) = pat.kind { + if ident.as_str().starts_with('_') + && !LocalUsedVisitor::new(cx, id).check_expr(arm.body) + { ident_bind_name = (&ident.name.as_str()).to_string(); matching_wild = true; } diff --git a/src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs b/src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs new file mode 100644 index 0000000000000..defc50ede2243 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs @@ -0,0 +1,39 @@ +use crate::utils::{is_type_diagnostic_item, snippet_with_applicability, span_lint_and_sugg}; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::LateContext; +use rustc_span::sym; + +use super::BYTES_NTH; + +pub(super) fn lints<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, iter_args: &'tcx [Expr<'tcx>]) { + if_chain! { + if let ExprKind::MethodCall(_, _, ref args, _) = expr.kind; + let ty = cx.typeck_results().expr_ty(&iter_args[0]).peel_refs(); + let caller_type = if is_type_diagnostic_item(cx, ty, sym::string_type) { + Some("String") + } else if ty.is_str() { + Some("str") + } else { + None + }; + if let Some(caller_type) = caller_type; + then { + let mut applicability = Applicability::MachineApplicable; + span_lint_and_sugg( + cx, + BYTES_NTH, + expr.span, + &format!("called `.byte().nth()` on a `{}`", caller_type), + "try", + format!( + "{}.as_bytes().get({})", + snippet_with_applicability(cx, iter_args[0].span, "..", &mut applicability), + snippet_with_applicability(cx, args[1].span, "..", &mut applicability) + ), + applicability, + ); + } + } +} diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map_identity.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map_identity.rs new file mode 100644 index 0000000000000..9e646360a40c3 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/methods/filter_map_identity.rs @@ -0,0 +1,52 @@ +use crate::utils::{match_qpath, match_trait_method, path_to_local_id, paths, span_lint_and_sugg}; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_lint::LateContext; +use rustc_span::source_map::Span; + +use super::FILTER_MAP_IDENTITY; + +pub(super) fn check( + cx: &LateContext<'_>, + expr: &hir::Expr<'_>, + filter_map_args: &[hir::Expr<'_>], + filter_map_span: Span, +) { + if match_trait_method(cx, expr, &paths::ITERATOR) { + let arg_node = &filter_map_args[1].kind; + + let apply_lint = |message: &str| { + span_lint_and_sugg( + cx, + FILTER_MAP_IDENTITY, + filter_map_span.with_hi(expr.span.hi()), + message, + "try", + "flatten()".to_string(), + Applicability::MachineApplicable, + ); + }; + + if_chain! { + if let hir::ExprKind::Closure(_, _, body_id, _, _) = arg_node; + let body = cx.tcx.hir().body(*body_id); + + if let hir::PatKind::Binding(_, binding_id, ..) = body.params[0].pat.kind; + if path_to_local_id(&body.value, binding_id); + then { + apply_lint("called `filter_map(|x| x)` on an `Iterator`"); + } + } + + if_chain! { + if let hir::ExprKind::Path(ref qpath) = arg_node; + + if match_qpath(qpath, &paths::STD_CONVERT_IDENTITY); + + then { + apply_lint("called `filter_map(std::convert::identity)` on an `Iterator`"); + } + } + } +} diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs index 0918843294d47..433f513b1a8bf 100644 --- a/src/tools/clippy/clippy_lints/src/methods/mod.rs +++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs @@ -1,4 +1,6 @@ mod bind_instead_of_map; +mod bytes_nth; +mod filter_map_identity; mod inefficient_to_string; mod inspect_for_each; mod manual_saturating_arithmetic; @@ -15,8 +17,7 @@ use if_chain::if_chain; use rustc_ast::ast; use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_hir::def::Res; -use rustc_hir::{Expr, ExprKind, PatKind, QPath, TraitItem, TraitItemKind, UnOp}; +use rustc_hir::{Expr, ExprKind, PatKind, 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}; @@ -30,12 +31,12 @@ use crate::consts::{constant, Constant}; use crate::utils::eager_or_lazy::is_lazyness_candidate; use crate::utils::usage::mutated_variables; use crate::utils::{ - contains_return, contains_ty, get_arg_name, get_parent_expr, get_trait_def_id, has_iter_method, higher, - implements_trait, in_macro, is_copy, is_expn_of, is_type_diagnostic_item, iter_input_pats, last_path_segment, - match_def_path, match_qpath, match_trait_method, match_type, match_var, meets_msrv, method_calls, - method_chain_args, paths, remove_blocks, return_ty, single_segment_path, snippet, snippet_with_applicability, - snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then, sugg, - walk_ptrs_ty_depth, SpanlessEq, + contains_return, contains_ty, get_parent_expr, get_trait_def_id, has_iter_method, higher, implements_trait, + in_macro, is_copy, is_expn_of, is_type_diagnostic_item, iter_input_pats, last_path_segment, match_def_path, + match_qpath, match_trait_method, match_type, meets_msrv, method_calls, method_chain_args, path_to_local_id, paths, + remove_blocks, return_ty, single_segment_path, snippet, snippet_with_applicability, snippet_with_macro_callsite, + span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then, strip_pat_refs, sugg, walk_ptrs_ty_depth, + SpanlessEq, }; declare_clippy_lint! { @@ -1467,6 +1468,51 @@ declare_clippy_lint! { "using `.inspect().for_each()`, which can be replaced with `.for_each()`" } +declare_clippy_lint! { + /// **What it does:** Checks for usage of `filter_map(|x| x)`. + /// + /// **Why is this bad?** Readability, this can be written more concisely by using `flatten`. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust + /// # let iter = vec![Some(1)].into_iter(); + /// iter.filter_map(|x| x); + /// ``` + /// Use instead: + /// ```rust + /// # let iter = vec![Some(1)].into_iter(); + /// iter.flatten(); + /// ``` + pub FILTER_MAP_IDENTITY, + complexity, + "call to `filter_map` where `flatten` is sufficient" +} + +declare_clippy_lint! { + /// **What it does:** Checks for the use of `.bytes().nth()`. + /// + /// **Why is this bad?** `.as_bytes().get()` is more efficient and more + /// readable. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust + /// // Bad + /// let _ = "Hello".bytes().nth(3); + /// + /// // Good + /// let _ = "Hello".as_bytes().get(3); + /// ``` + pub BYTES_NTH, + style, + "replace `.bytes().nth()` with `.as_bytes().get()`" +} + pub struct Methods { msrv: Option, } @@ -1504,6 +1550,7 @@ impl_lint_pass!(Methods => [ FILTER_NEXT, SKIP_WHILE_NEXT, FILTER_MAP, + FILTER_MAP_IDENTITY, MANUAL_FILTER_MAP, MANUAL_FIND_MAP, FILTER_MAP_NEXT, @@ -1513,6 +1560,7 @@ impl_lint_pass!(Methods => [ ITER_NEXT_SLICE, ITER_NTH, ITER_NTH_ZERO, + BYTES_NTH, ITER_SKIP_NEXT, GET_UNWRAP, STRING_EXTEND_CHARS, @@ -1590,6 +1638,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { ["extend", ..] => lint_extend(cx, expr, arg_lists[0]), ["nth", "iter"] => lint_iter_nth(cx, expr, &arg_lists, false), ["nth", "iter_mut"] => lint_iter_nth(cx, expr, &arg_lists, true), + ["nth", "bytes"] => bytes_nth::lints(cx, expr, &arg_lists[1]), ["nth", ..] => lint_iter_nth_zero(cx, expr, arg_lists[0]), ["step_by", ..] => lint_step_by(cx, expr, arg_lists[0]), ["next", "skip"] => lint_iter_skip_next(cx, expr, arg_lists[1]), @@ -1597,7 +1646,10 @@ impl<'tcx> LateLintPass<'tcx> for Methods { ["as_ref"] => lint_asref(cx, expr, "as_ref", arg_lists[0]), ["as_mut"] => lint_asref(cx, expr, "as_mut", arg_lists[0]), ["fold", ..] => lint_unnecessary_fold(cx, expr, arg_lists[0], method_spans[0]), - ["filter_map", ..] => unnecessary_filter_map::lint(cx, expr, arg_lists[0]), + ["filter_map", ..] => { + unnecessary_filter_map::lint(cx, expr, arg_lists[0]); + filter_map_identity::check(cx, expr, arg_lists[0], method_spans[0]); + }, ["count", "map"] => lint_suspicious_map(cx, expr), ["assume_init"] => lint_maybe_uninit(cx, &arg_lists[0][0], expr), ["unwrap_or", arith @ ("checked_add" | "checked_sub" | "checked_mul")] => { @@ -2183,7 +2235,10 @@ fn lint_expect_fun_call( span_replace_word, &format!("use of `{}` followed by a function call", name), "try this", - format!("unwrap_or_else({} {{ panic!(\"{{}}\", {}) }})", closure_args, arg_root_snippet), + format!( + "unwrap_or_else({} {{ panic!(\"{{}}\", {}) }})", + closure_args, arg_root_snippet + ), applicability, ); } @@ -2396,11 +2451,12 @@ fn lint_unnecessary_fold(cx: &LateContext<'_>, expr: &hir::Expr<'_>, fold_args: if bin_op.node == op; // Extract the names of the two arguments to the closure - if let Some(first_arg_ident) = get_arg_name(&closure_body.params[0].pat); - if let Some(second_arg_ident) = get_arg_name(&closure_body.params[1].pat); + if let [param_a, param_b] = closure_body.params; + if let PatKind::Binding(_, first_arg_id, ..) = strip_pat_refs(¶m_a.pat).kind; + if let PatKind::Binding(_, second_arg_id, second_arg_ident, _) = strip_pat_refs(¶m_b.pat).kind; - if match_var(&*left_expr, first_arg_ident); - if replacement_has_args || match_var(&*right_expr, second_arg_ident); + if path_to_local_id(left_expr, first_arg_id); + if replacement_has_args || path_to_local_id(right_expr, second_arg_id); then { let mut applicability = Applicability::MachineApplicable; @@ -3068,10 +3124,8 @@ fn lint_filter_map<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, is_f }; // 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 path_to_local_id(a_path, filter_param_id); + if path_to_local_id(b, map_param_id); if TyS::same_type(cx.typeck_results().expr_ty_adjusted(a), cx.typeck_results().expr_ty_adjusted(b)); then { return true; @@ -3255,8 +3309,9 @@ fn lint_search_is_some<'tcx>( then { if let hir::PatKind::Ref(..) = closure_arg.pat.kind { Some(search_snippet.replacen('&', "", 1)) - } else if let Some(name) = get_arg_name(&closure_arg.pat) { - Some(search_snippet.replace(&format!("*{}", name), &name.as_str())) + } else if let PatKind::Binding(_, _, ident, _) = strip_pat_refs(&closure_arg.pat).kind { + let name = &*ident.name.as_str(); + Some(search_snippet.replace(&format!("*{}", name), name)) } else { None } @@ -3688,9 +3743,7 @@ fn lint_option_as_ref_deref<'tcx>( hir::ExprKind::MethodCall(_, _, args, _) => { if_chain! { if args.len() == 1; - if let hir::ExprKind::Path(qpath) = &args[0].kind; - if let hir::def::Res::Local(local_id) = cx.qpath_res(qpath, args[0].hir_id); - if closure_body.params[0].pat.hir_id == local_id; + if path_to_local_id(&args[0], closure_body.params[0].pat.hir_id); let adj = cx .typeck_results() .expr_adjustments(&args[0]) @@ -3710,10 +3763,8 @@ fn lint_option_as_ref_deref<'tcx>( if_chain! { if let hir::ExprKind::Unary(hir::UnOp::Deref, ref inner1) = inner.kind; if let hir::ExprKind::Unary(hir::UnOp::Deref, ref inner2) = inner1.kind; - if let hir::ExprKind::Path(ref qpath) = inner2.kind; - if let hir::def::Res::Local(local_id) = cx.qpath_res(qpath, inner2.hir_id); then { - closure_body.params[0].pat.hir_id == local_id + path_to_local_id(inner2, closure_body.params[0].pat.hir_id) } else { false } @@ -4094,20 +4145,54 @@ fn lint_from_iter(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr< if implements_trait(cx, ty, from_iter_id, &[]) && implements_trait(cx, arg_ty, iter_id, &[]); then { // `expr` implements `FromIterator` trait - let iter_expr = snippet(cx, args[0].span, ".."); + let iter_expr = sugg::Sugg::hir(cx, &args[0], "..").maybe_par(); + let turbofish = extract_turbofish(cx, expr, ty); + let sugg = format!("{}.collect::<{}>()", iter_expr, turbofish); span_lint_and_sugg( cx, FROM_ITER_INSTEAD_OF_COLLECT, expr.span, "usage of `FromIterator::from_iter`", "use `.collect()` instead of `::from_iter()`", - format!("{}.collect()", iter_expr), + sugg, Applicability::MaybeIncorrect, ); } } } +fn extract_turbofish(cx: &LateContext<'_>, expr: &hir::Expr<'_>, ty: Ty<'tcx>) -> String { + if_chain! { + let call_site = expr.span.source_callsite(); + if let Ok(snippet) = cx.sess().source_map().span_to_snippet(call_site); + let snippet_split = snippet.split("::").collect::>(); + if let Some((_, elements)) = snippet_split.split_last(); + + then { + // is there a type specifier? (i.e.: like `` in `collections::BTreeSet::::`) + if let Some(type_specifier) = snippet_split.iter().find(|e| e.starts_with('<') && e.ends_with('>')) { + // remove the type specifier from the path elements + let without_ts = elements.iter().filter_map(|e| { + if e == type_specifier { None } else { Some((*e).to_string()) } + }).collect::>(); + // join and add the type specifier at the end (i.e.: `collections::BTreeSet`) + format!("{}{}", without_ts.join("::"), type_specifier) + } else { + // type is not explicitly specified so wildcards are needed + // i.e.: 2 wildcards in `std::collections::BTreeMap<&i32, &char>` + let ty_str = ty.to_string(); + let start = ty_str.find('<').unwrap_or(0); + let end = ty_str.find('>').unwrap_or_else(|| ty_str.len()); + let nb_wildcard = ty_str[start..end].split(',').count(); + let wildcards = format!("_{}", ", _".repeat(nb_wildcard - 1)); + format!("{}<{}>", elements.join("::"), wildcards) + } + } else { + ty.to_string() + } + } +} + fn fn_header_equals(expected: hir::FnHeader, actual: hir::FnHeader) -> bool { expected.constness == actual.constness && expected.unsafety == actual.unsafety diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs index d98e6160d3085..5691fcb88e95c 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs @@ -1,8 +1,6 @@ -use crate::utils::paths; use crate::utils::usage::mutated_variables; -use crate::utils::{match_qpath, match_trait_method, span_lint}; +use crate::utils::{match_qpath, match_trait_method, path_to_local_id, paths, span_lint}; use rustc_hir as hir; -use rustc_hir::def::Res; use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; use rustc_lint::LateContext; use rustc_middle::hir::map::Map; @@ -59,14 +57,8 @@ fn check_expression<'tcx>(cx: &LateContext<'tcx>, arg_id: hir::HirId, expr: &'tc if let hir::ExprKind::Path(ref path) = func.kind; then { if match_qpath(path, &paths::OPTION_SOME) { - if_chain! { - if let hir::ExprKind::Path(path) = &args[0].kind; - if let Res::Local(ref local) = cx.qpath_res(path, args[0].hir_id); - then { - if arg_id == *local { - return (false, false) - } - } + if path_to_local_id(&args[0], arg_id) { + return (false, false) } return (true, false); } diff --git a/src/tools/clippy/clippy_lints/src/mut_mut.rs b/src/tools/clippy/clippy_lints/src/mut_mut.rs index 2f3cdb894f01c..d7239b328bbcd 100644 --- a/src/tools/clippy/clippy_lints/src/mut_mut.rs +++ b/src/tools/clippy/clippy_lints/src/mut_mut.rs @@ -52,7 +52,7 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for MutVisitor<'a, 'tcx> { return; } - if let Some((_, arg, body)) = higher::for_loop(expr) { + if let Some((_, arg, body, _)) = higher::for_loop(expr) { // A `for` loop lowers to: // ```rust // match ::std::iter::Iterator::next(&mut iter) { diff --git a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs index 9e9b79ee1cf08..fe8d4d07abc15 100644 --- a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs +++ b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs @@ -1,8 +1,6 @@ use rustc_errors::Applicability; -use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; use rustc_hir::{Body, Expr, ExprKind, LangItem, MatchSource, QPath}; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::ty::DefIdTree; use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::sym; @@ -160,7 +158,7 @@ fn is_some_or_ok_call<'a>( // Check outer expression matches CALL_IDENT(ARGUMENT) format if let ExprKind::Call(path, args) = &expr.kind; if let ExprKind::Path(QPath::Resolved(None, path)) = &path.kind; - if is_some_ctor(cx, path.res) || is_ok_ctor(cx, path.res); + if utils::is_some_ctor(cx, path.res) || utils::is_ok_ctor(cx, path.res); // Extract inner expression from ARGUMENT if let ExprKind::Match(inner_expr_with_q, _, MatchSource::TryDesugar) = &args[0].kind; @@ -208,25 +206,3 @@ fn is_some_or_ok_call<'a>( fn has_implicit_error_from(cx: &LateContext<'_>, entire_expr: &Expr<'_>, inner_result_expr: &Expr<'_>) -> bool { return cx.typeck_results().expr_ty(entire_expr) != cx.typeck_results().expr_ty(inner_result_expr); } - -fn is_ok_ctor(cx: &LateContext<'_>, res: Res) -> bool { - if let Some(ok_id) = cx.tcx.lang_items().result_ok_variant() { - if let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Fn), id) = res { - if let Some(variant_id) = cx.tcx.parent(id) { - return variant_id == ok_id; - } - } - } - false -} - -fn is_some_ctor(cx: &LateContext<'_>, res: Res) -> bool { - if let Some(some_id) = cx.tcx.lang_items().option_some_variant() { - if let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Fn), id) = res { - if let Some(variant_id) = cx.tcx.parent(id) { - return variant_id == some_id; - } - } - } - false -} diff --git a/src/tools/clippy/clippy_lints/src/ranges.rs b/src/tools/clippy/clippy_lints/src/ranges.rs index 3e454eecd970e..59503817c0fcc 100644 --- a/src/tools/clippy/clippy_lints/src/ranges.rs +++ b/src/tools/clippy/clippy_lints/src/ranges.rs @@ -442,7 +442,7 @@ fn check_reversed_empty_range(cx: &LateContext<'_>, expr: &Expr<'_>) { let mut cur_expr = expr; while let Some(parent_expr) = get_parent_expr(cx, cur_expr) { match higher::for_loop(parent_expr) { - Some((_, args, _)) if args.hir_id == expr.hir_id => return true, + Some((_, args, _, _)) if args.hir_id == expr.hir_id => return true, _ => cur_expr = parent_expr, } } diff --git a/src/tools/clippy/clippy_lints/src/regex.rs b/src/tools/clippy/clippy_lints/src/regex.rs index d06ab14348237..1edea61314893 100644 --- a/src/tools/clippy/clippy_lints/src/regex.rs +++ b/src/tools/clippy/clippy_lints/src/regex.rs @@ -35,14 +35,16 @@ declare_clippy_lint! { /// `str::starts_with`, `str::ends_with` or `std::contains` or other `str` /// methods. /// - /// **Known problems:** None. + /// **Known problems:** If the same regex is going to be applied to multiple + /// inputs, the precomputations done by `Regex` construction can give + /// significantly better performance than any of the `str`-based methods. /// /// **Example:** /// ```ignore /// Regex::new("^foobar") /// ``` pub TRIVIAL_REGEX, - style, + nursery, "trivial regular expressions" } diff --git a/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs b/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs new file mode 100644 index 0000000000000..839c995e52562 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs @@ -0,0 +1,66 @@ +use crate::utils::{in_macro, snippet_with_macro_callsite, span_lint_and_sugg, sugg}; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir::{Block, ExprKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +declare_clippy_lint! { + /// **What it does:** Looks for blocks of expressions and fires if the last expression returns `()` + /// but is not followed by a semicolon. + /// + /// **Why is this bad?** The semicolon might be optional but when + /// extending the block with new code, it doesn't require a change in previous last line. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust + /// fn main() { + /// println!("Hello world") + /// } + /// ``` + /// Use instead: + /// ```rust + /// fn main() { + /// println!("Hello world"); + /// } + /// ``` + pub SEMICOLON_IF_NOTHING_RETURNED, + restriction, + "add a semicolon if nothing is returned" +} + +declare_lint_pass!(SemicolonIfNothingReturned => [SEMICOLON_IF_NOTHING_RETURNED]); + +impl LateLintPass<'_> for SemicolonIfNothingReturned { + fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) { + if_chain! { + if !in_macro(block.span); + if let Some(expr) = block.expr; + let t_expr = cx.typeck_results().expr_ty(expr); + if t_expr.is_unit(); + if let snippet = snippet_with_macro_callsite(cx, expr.span, "}"); + if !snippet.ends_with('}'); + then { + // filter out the desugared `for` loop + if let ExprKind::DropTemps(..) = &expr.kind { + return; + } + + let sugg = sugg::Sugg::hir_with_macro_callsite(cx, &expr, ".."); + let suggestion = format!("{0};", sugg); + span_lint_and_sugg( + cx, + SEMICOLON_IF_NOTHING_RETURNED, + expr.span.source_callsite(), + "consider adding a `;` to the last statement for consistent formatting", + "add a `;` here", + suggestion, + Applicability::MaybeIncorrect, + ); + } + } + } +} diff --git a/src/tools/clippy/clippy_lints/src/to_string_in_display.rs b/src/tools/clippy/clippy_lints/src/to_string_in_display.rs index fa508df865e48..fdd105e624605 100644 --- a/src/tools/clippy/clippy_lints/src/to_string_in_display.rs +++ b/src/tools/clippy/clippy_lints/src/to_string_in_display.rs @@ -1,6 +1,5 @@ -use crate::utils::{match_def_path, match_trait_method, paths, span_lint}; +use crate::utils::{match_def_path, match_trait_method, path_to_local_id, paths, span_lint}; use if_chain::if_chain; -use rustc_hir::def::Res; use rustc_hir::{Expr, ExprKind, HirId, Impl, ImplItem, ImplItemKind, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; @@ -89,14 +88,12 @@ impl LateLintPass<'_> for ToStringInDisplay { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { if_chain! { + if self.in_display_impl; + if let Some(self_hir_id) = self.self_hir_id; if let ExprKind::MethodCall(ref path, _, args, _) = expr.kind; if path.ident.name == sym!(to_string); if match_trait_method(cx, expr, &paths::TO_STRING); - if self.in_display_impl; - if let ExprKind::Path(ref qpath) = args[0].kind; - if let Res::Local(hir_id) = cx.qpath_res(qpath, args[0].hir_id); - if let Some(self_hir_id) = self.self_hir_id; - if hir_id == self_hir_id; + if path_to_local_id(&args[0], self_hir_id); then { span_lint( cx, diff --git a/src/tools/clippy/clippy_lints/src/unused_self.rs b/src/tools/clippy/clippy_lints/src/unused_self.rs index 5349c4f7eb8a7..9d61bd0cc2fe9 100644 --- a/src/tools/clippy/clippy_lints/src/unused_self.rs +++ b/src/tools/clippy/clippy_lints/src/unused_self.rs @@ -1,12 +1,10 @@ use if_chain::if_chain; -use rustc_hir::def::Res; -use rustc_hir::intravisit::{walk_path, NestedVisitorMap, Visitor}; -use rustc_hir::{HirId, Impl, ImplItem, ImplItemKind, ItemKind, Path}; +use rustc_hir::{Impl, ImplItem, ImplItemKind, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::hir::map::Map; use rustc_session::{declare_lint_pass, declare_tool_lint}; use crate::utils::span_lint_and_help; +use crate::utils::visitors::LocalUsedVisitor; declare_clippy_lint! { /// **What it does:** Checks methods that contain a `self` argument but don't use it @@ -57,13 +55,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedSelf { then { let self_param = &body.params[0]; let self_hir_id = self_param.pat.hir_id; - let mut visitor = UnusedSelfVisitor { - cx, - uses_self: false, - self_hir_id: &self_hir_id, - }; - visitor.visit_body(body); - if !visitor.uses_self { + if !LocalUsedVisitor::new(cx, self_hir_id).check_body(body) { span_lint_and_help( cx, UNUSED_SELF, @@ -78,28 +70,3 @@ impl<'tcx> LateLintPass<'tcx> for UnusedSelf { } } } - -struct UnusedSelfVisitor<'a, 'tcx> { - cx: &'a LateContext<'tcx>, - uses_self: bool, - self_hir_id: &'a HirId, -} - -impl<'a, 'tcx> Visitor<'tcx> for UnusedSelfVisitor<'a, 'tcx> { - type Map = Map<'tcx>; - - fn visit_path(&mut self, path: &'tcx Path<'_>, _id: HirId) { - if self.uses_self { - // This function already uses `self` - return; - } - if let Res::Local(hir_id) = &path.res { - self.uses_self = self.self_hir_id == hir_id - } - walk_path(self, path); - } - - fn nested_visit_map(&mut self) -> NestedVisitorMap { - NestedVisitorMap::OnlyBodies(self.cx.tcx.hir()) - } -} diff --git a/src/tools/clippy/clippy_lints/src/utils/conf.rs b/src/tools/clippy/clippy_lints/src/utils/conf.rs index b5a8300376c16..7d7b35c21680d 100644 --- a/src/tools/clippy/clippy_lints/src/utils/conf.rs +++ b/src/tools/clippy/clippy_lints/src/utils/conf.rs @@ -169,10 +169,12 @@ define_Conf! { (max_fn_params_bools, "max_fn_params_bools": u64, 3), /// Lint: WILDCARD_IMPORTS. Whether to allow certain wildcard imports (prelude, super in tests). (warn_on_all_wildcard_imports, "warn_on_all_wildcard_imports": bool, false), - /// Lint: DISALLOWED_METHOD. The list of blacklisted methods to lint about. NB: `bar` is not here since it has legitimate uses + /// Lint: DISALLOWED_METHOD. The list of disallowed methods, written as fully qualified paths. (disallowed_methods, "disallowed_methods": Vec, Vec::::new()), /// Lint: UNREADABLE_LITERAL. Should the fraction of a decimal be linted to include separators. (unreadable_literal_lint_fractions, "unreadable_literal_lint_fractions": bool, true), + /// Lint: _CARGO_COMMON_METADATA. For internal testing only, ignores the current `publish` settings in the Cargo manifest. + (cargo_ignore_publish, "cargo_ignore_publish": bool, false), } impl Default for Conf { diff --git a/src/tools/clippy/clippy_lints/src/utils/higher.rs b/src/tools/clippy/clippy_lints/src/utils/higher.rs index 145703d1bdc3f..1cf1aa363d5dd 100644 --- a/src/tools/clippy/clippy_lints/src/utils/higher.rs +++ b/src/tools/clippy/clippy_lints/src/utils/higher.rs @@ -9,6 +9,7 @@ use rustc_ast::ast; use rustc_hir as hir; use rustc_hir::{BorrowKind, Expr, ExprKind, StmtKind, UnOp}; use rustc_lint::LateContext; +use rustc_span::source_map::Span; /// Converts a hir binary operator to the corresponding `ast` type. #[must_use] @@ -133,11 +134,11 @@ pub fn is_from_for_desugar(local: &hir::Local<'_>) -> bool { false } -/// Recover the essential nodes of a desugared for loop: -/// `for pat in arg { body }` becomes `(pat, arg, body)`. +/// Recover the essential nodes of a desugared for loop as well as the entire span: +/// `for pat in arg { body }` becomes `(pat, arg, body)`. Return `(pat, arg, body, span)`. pub fn for_loop<'tcx>( expr: &'tcx hir::Expr<'tcx>, -) -> Option<(&hir::Pat<'_>, &'tcx hir::Expr<'tcx>, &'tcx hir::Expr<'tcx>)> { +) -> Option<(&hir::Pat<'_>, &'tcx hir::Expr<'tcx>, &'tcx hir::Expr<'tcx>, Span)> { if_chain! { if let hir::ExprKind::Match(ref iterexpr, ref arms, hir::MatchSource::ForLoopDesugar) = expr.kind; if let hir::ExprKind::Call(_, ref iterargs) = iterexpr.kind; @@ -148,7 +149,7 @@ pub fn for_loop<'tcx>( if let hir::StmtKind::Local(ref local) = let_stmt.kind; if let hir::StmtKind::Expr(ref expr) = body.kind; then { - return Some((&*local.pat, &iterargs[0], expr)); + return Some((&*local.pat, &iterargs[0], expr, arms[0].span)); } } None diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs index ff3be590317ba..d8c602fab22c2 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs @@ -841,15 +841,13 @@ pub fn check_path(cx: &LateContext<'_>, path: &[&str]) -> bool { // implementations of native types. Check lang items. let path_syms: Vec<_> = path.iter().map(|p| Symbol::intern(p)).collect(); let lang_items = cx.tcx.lang_items(); - for lang_item in lang_items.items() { - if let Some(def_id) = lang_item { - let lang_item_path = cx.get_def_path(*def_id); - if path_syms.starts_with(&lang_item_path) { - if let [item] = &path_syms[lang_item_path.len()..] { - for child in cx.tcx.item_children(*def_id) { - if child.ident.name == *item { - return true; - } + for item_def_id in lang_items.items().iter().flatten() { + let lang_item_path = cx.get_def_path(*item_def_id); + if path_syms.starts_with(&lang_item_path) { + if let [item] = &path_syms[lang_item_path.len()..] { + for child in cx.tcx.item_children(*item_def_id) { + if child.ident.name == *item { + return true; } } } diff --git a/src/tools/clippy/clippy_lints/src/utils/mod.rs b/src/tools/clippy/clippy_lints/src/utils/mod.rs index de1538233a8c3..fafa1400156a4 100644 --- a/src/tools/clippy/clippy_lints/src/utils/mod.rs +++ b/src/tools/clippy/clippy_lints/src/utils/mod.rs @@ -36,7 +36,7 @@ use rustc_ast::ast::{self, Attribute, LitKind}; 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::{CtorKind, CtorOf, DefKind, Res}; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::Node; @@ -49,7 +49,7 @@ 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}; +use rustc_middle::ty::{self, layout::IntegerExt, DefIdTree, Ty, TyCtxt, TypeFoldable}; use rustc_semver::RustcVersion; use rustc_session::Session; use rustc_span::hygiene::{ExpnKind, MacroKind}; @@ -306,6 +306,22 @@ pub fn match_path_ast(path: &ast::Path, segments: &[&str]) -> bool { .all(|(a, b)| a.ident.name.as_str() == *b) } +/// If the expression is a path to a local, returns the canonical `HirId` of the local. +pub fn path_to_local(expr: &Expr<'_>) -> Option { + if let ExprKind::Path(QPath::Resolved(None, ref path)) = expr.kind { + if let Res::Local(id) = path.res { + return Some(id); + } + } + None +} + +/// Returns true if the expression is a path to a local with the specified `HirId`. +/// Use this function to see if an expression matches a function argument or a match binding. +pub fn path_to_local_id(expr: &Expr<'_>, id: HirId) -> bool { + path_to_local(expr) == Some(id) +} + /// Gets the definition associated to a path. #[allow(clippy::shadow_unrelated)] // false positive #6563 pub fn path_to_res(cx: &LateContext<'_>, path: &[&str]) -> Res { @@ -1134,9 +1150,7 @@ pub fn is_try<'tcx>(expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> { if let PatKind::TupleStruct(ref path, ref pat, None) = arm.pat.kind; if match_qpath(path, &paths::RESULT_OK[1..]); if let PatKind::Binding(_, hir_id, _, None) = pat[0].kind; - if let ExprKind::Path(QPath::Resolved(None, ref path)) = arm.body.kind; - if let Res::Local(lid) = path.res; - if lid == hir_id; + if path_to_local_id(arm.body, hir_id); then { return true; } @@ -1180,12 +1194,11 @@ pub fn is_allowed(cx: &LateContext<'_>, lint: &'static Lint, id: HirId) -> bool cx.tcx.lint_level_at_node(lint, id).0 == Level::Allow } -pub fn get_arg_name(pat: &Pat<'_>) -> Option { - match pat.kind { - PatKind::Binding(.., ident, None) => Some(ident.name), - PatKind::Ref(ref subpat, _) => get_arg_name(subpat), - _ => None, +pub fn strip_pat_refs<'hir>(mut pat: &'hir Pat<'hir>) -> &'hir Pat<'hir> { + while let PatKind::Ref(subpat, _) = pat.kind { + pat = subpat; } + pat } pub fn int_bits(tcx: TyCtxt<'_>, ity: ty::IntTy) -> u64 { @@ -1702,6 +1715,30 @@ pub fn is_hir_ty_cfg_dependant(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> bool { } } +/// Check if the resolution of a given path is an `Ok` variant of `Result`. +pub fn is_ok_ctor(cx: &LateContext<'_>, res: Res) -> bool { + if let Some(ok_id) = cx.tcx.lang_items().result_ok_variant() { + if let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Fn), id) = res { + if let Some(variant_id) = cx.tcx.parent(id) { + return variant_id == ok_id; + } + } + } + false +} + +/// Check if the resolution of a given path is a `Some` variant of `Option`. +pub fn is_some_ctor(cx: &LateContext<'_>, res: Res) -> bool { + if let Some(some_id) = cx.tcx.lang_items().option_some_variant() { + if let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Fn), id) = res { + if let Some(variant_id) = cx.tcx.parent(id) { + return variant_id == some_id; + } + } + } + false +} + #[cfg(test)] mod test { use super::{reindent_multiline, without_block_comments}; diff --git a/src/tools/clippy/clippy_lints/src/utils/usage.rs b/src/tools/clippy/clippy_lints/src/utils/usage.rs index fc0db7f64ec95..7c7580a2c6612 100644 --- a/src/tools/clippy/clippy_lints/src/utils/usage.rs +++ b/src/tools/clippy/clippy_lints/src/utils/usage.rs @@ -1,16 +1,14 @@ use crate::utils; -use crate::utils::match_var; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::intravisit; -use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; +use rustc_hir::intravisit::{NestedVisitorMap, Visitor}; use rustc_hir::{Expr, ExprKind, HirId, Path}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::LateContext; use rustc_middle::hir::map::Map; use rustc_middle::ty; -use rustc_span::symbol::{Ident, Symbol}; use rustc_typeck::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId}; /// Returns a set of mutated local variable IDs, or `None` if mutations could not be determined. @@ -81,36 +79,6 @@ impl<'tcx> Delegate<'tcx> for MutVarsDelegate { } } -pub struct UsedVisitor { - pub var: Symbol, // var to look for - pub used: bool, // has the var been used otherwise? -} - -impl<'tcx> Visitor<'tcx> for UsedVisitor { - type Map = Map<'tcx>; - - fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { - if match_var(expr, self.var) { - self.used = true; - } else { - walk_expr(self, expr); - } - } - - fn nested_visit_map(&mut self) -> NestedVisitorMap { - NestedVisitorMap::None - } -} - -pub fn is_unused<'tcx>(ident: &'tcx Ident, body: &'tcx Expr<'_>) -> bool { - let mut visitor = UsedVisitor { - var: ident.name, - used: false, - }; - walk_expr(&mut visitor, body); - !visitor.used -} - pub struct ParamBindingIdCollector { binding_hir_ids: Vec, } diff --git a/src/tools/clippy/clippy_lints/src/utils/visitors.rs b/src/tools/clippy/clippy_lints/src/utils/visitors.rs index ebf69df31ca41..085c1f9c0cb8d 100644 --- a/src/tools/clippy/clippy_lints/src/utils/visitors.rs +++ b/src/tools/clippy/clippy_lints/src/utils/visitors.rs @@ -1,7 +1,7 @@ +use crate::utils::path_to_local_id; use rustc_hir as hir; -use rustc_hir::def::Res; use rustc_hir::intravisit::{self, walk_expr, NestedVisitorMap, Visitor}; -use rustc_hir::{Arm, Expr, ExprKind, HirId, QPath, Stmt}; +use rustc_hir::{Arm, Body, Expr, HirId, Stmt}; use rustc_lint::LateContext; use rustc_middle::hir::map::Map; @@ -133,14 +133,16 @@ where } } -pub struct LocalUsedVisitor { +pub struct LocalUsedVisitor<'hir> { + hir: Map<'hir>, pub local_hir_id: HirId, pub used: bool, } -impl LocalUsedVisitor { - pub fn new(local_hir_id: HirId) -> Self { +impl<'hir> LocalUsedVisitor<'hir> { + pub fn new(cx: &LateContext<'hir>, local_hir_id: HirId) -> Self { Self { + hir: cx.tcx.hir(), local_hir_id, used: false, } @@ -151,35 +153,38 @@ impl LocalUsedVisitor { std::mem::replace(&mut self.used, false) } - pub fn check_arm(&mut self, arm: &Arm<'_>) -> bool { + pub fn check_arm(&mut self, arm: &'hir Arm<'_>) -> bool { self.check(arm, Self::visit_arm) } - pub fn check_expr(&mut self, expr: &Expr<'_>) -> bool { + pub fn check_body(&mut self, body: &'hir Body<'_>) -> bool { + self.check(body, Self::visit_body) + } + + pub fn check_expr(&mut self, expr: &'hir Expr<'_>) -> bool { self.check(expr, Self::visit_expr) } - pub fn check_stmt(&mut self, stmt: &Stmt<'_>) -> bool { + pub fn check_stmt(&mut self, stmt: &'hir Stmt<'_>) -> bool { self.check(stmt, Self::visit_stmt) } } -impl<'v> Visitor<'v> for LocalUsedVisitor { +impl<'v> Visitor<'v> for LocalUsedVisitor<'v> { type Map = Map<'v>; fn visit_expr(&mut self, expr: &'v Expr<'v>) { - if let ExprKind::Path(QPath::Resolved(None, path)) = expr.kind { - if let Res::Local(id) = path.res { - if id == self.local_hir_id { - self.used = true; - return; - } - } + if self.used { + return; + } + if path_to_local_id(expr, self.local_hir_id) { + self.used = true; + } else { + walk_expr(self, expr); } - walk_expr(self, expr); } fn nested_visit_map(&mut self) -> NestedVisitorMap { - NestedVisitorMap::None + NestedVisitorMap::OnlyBodies(self.hir) } } diff --git a/src/tools/clippy/clippy_lints/src/vec.rs b/src/tools/clippy/clippy_lints/src/vec.rs index 149cceb39dd99..c132e4de4f67b 100644 --- a/src/tools/clippy/clippy_lints/src/vec.rs +++ b/src/tools/clippy/clippy_lints/src/vec.rs @@ -55,7 +55,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessVec { // search for `for _ in vec![…]` if_chain! { - if let Some((_, arg, _)) = higher::for_loop(expr); + if let Some((_, arg, _, _)) = higher::for_loop(expr); if let Some(vec_args) = higher::vec_macro(cx, arg); if is_copy(cx, vec_type(cx.typeck_results().expr_ty_adjusted(arg))); then { diff --git a/src/tools/clippy/lintcheck-logs/logs.txt b/src/tools/clippy/lintcheck-logs/lintcheck_crates_logs.txt similarity index 94% rename from src/tools/clippy/lintcheck-logs/logs.txt rename to src/tools/clippy/lintcheck-logs/lintcheck_crates_logs.txt index e565691e0e396..3bc7758033b28 100644 --- a/src/tools/clippy/lintcheck-logs/logs.txt +++ b/src/tools/clippy/lintcheck-logs/lintcheck_crates_logs.txt @@ -1,6 +1,6 @@ -clippy 0.1.51 (c6701036b 2021-01-23) +clippy 0.1.51 (7f5bb7fd0 2021-02-06) -cargo-0.49.0//home/matthias/.rustup/toolchains/nightly-2021-01-15-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/macros/mod.rs:393:34 clippy::match_same_arms "this `match` has identical arm bodies" +cargo-0.49.0//home/matthias/.rustup/toolchains/nightly-2021-02-03-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/macros/mod.rs:409:34 clippy::match_same_arms "this `match` has identical arm bodies" cargo-0.49.0/build.rs:1:null clippy::cargo_common_metadata "package `cargo` is missing `package.categories` metadata" cargo-0.49.0/build.rs:1:null clippy::cargo_common_metadata "package `cargo` is missing `package.keywords` metadata" cargo-0.49.0/src/bin/cargo/cli.rs:104:34 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`" @@ -99,6 +99,7 @@ cargo-0.49.0/src/cargo/core/compiler/build_context/target_info.rs:411:9 clippy:: cargo-0.49.0/src/cargo/core/compiler/build_context/target_info.rs:420:69 clippy::doc_markdown "you should put `mode/target_kind` between ticks in the documentation" cargo-0.49.0/src/cargo/core/compiler/build_context/target_info.rs:423:19 clippy::doc_markdown "you should put `CrateTypes` between ticks in the documentation" cargo-0.49.0/src/cargo/core/compiler/build_context/target_info.rs:424:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/core/compiler/build_context/target_info.rs:424:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/core/compiler/build_context/target_info.rs:469:58 clippy::redundant_closure_for_method_calls "redundant closure found" cargo-0.49.0/src/cargo/core/compiler/build_context/target_info.rs:603:19 clippy::redundant_closure_for_method_calls "redundant closure found" cargo-0.49.0/src/cargo/core/compiler/build_context/target_info.rs:665:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" @@ -111,6 +112,7 @@ cargo-0.49.0/src/cargo/core/compiler/build_plan.rs:4:9 clippy::doc_markdown "you cargo-0.49.0/src/cargo/core/compiler/build_plan.rs:5:66 clippy::doc_markdown "you should put `BuildPlan` between ticks in the documentation" cargo-0.49.0/src/cargo/core/compiler/build_plan.rs:66:40 clippy::ptr_arg "writing `&PathBuf` instead of `&Path` involves a new object where a slice will do." cargo-0.49.0/src/cargo/core/compiler/compilation.rs:150:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/core/compiler/compilation.rs:150:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/core/compiler/compilation.rs:169:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/core/compiler/compilation.rs:185:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/core/compiler/compilation.rs:193:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" @@ -121,6 +123,7 @@ cargo-0.49.0/src/cargo/core/compiler/compilation.rs:91:5 clippy::missing_errors_ cargo-0.49.0/src/cargo/core/compiler/compile_kind.rs:118:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/core/compiler/compile_kind.rs:123:18 clippy::case_sensitive_file_extension_comparisons "case-sensitive file extension comparison" cargo-0.49.0/src/cargo/core/compiler/compile_kind.rs:147:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" +cargo-0.49.0/src/cargo/core/compiler/compile_kind.rs:157:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/core/compiler/compile_kind.rs:157:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/compiler/compile_kind.rs:29:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/compiler/compile_kind.rs:33:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" @@ -132,18 +135,23 @@ cargo-0.49.0/src/cargo/core/compiler/context/compilation_files.rs:324:66 clippy: cargo-0.49.0/src/cargo/core/compiler/context/compilation_files.rs:393:37 clippy::match_same_arms "this `match` has identical arm bodies" cargo-0.49.0/src/cargo/core/compiler/context/compilation_files.rs:426:71 clippy::redundant_closure_for_method_calls "redundant closure found" cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:125:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:125:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:125:5 clippy::too_many_lines "this function has too many lines (107/100)" cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:270:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:286:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:308:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:308:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" +cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:340:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:340:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:349:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:349:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:354:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:358:21 clippy::doc_markdown "you should put `RunCustomBuild` between ticks in the documentation" cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:361:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:374:43 clippy::doc_markdown "you should put `RunCustomBuild` between ticks in the documentation" cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:378:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:383:41 clippy::doc_markdown "you should put `RunCustomBuild` between ticks in the documentation" +cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:384:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:384:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:391:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/compiler/context/mod.rs:397:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" @@ -162,8 +170,10 @@ cargo-0.49.0/src/cargo/core/compiler/custom_build.rs:353:56 clippy::manual_strip cargo-0.49.0/src/cargo/core/compiler/custom_build.rs:448:27 clippy::needless_pass_by_value "this argument is passed by value, but not consumed in the function body" cargo-0.49.0/src/cargo/core/compiler/custom_build.rs:464:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/core/compiler/custom_build.rs:481:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/core/compiler/custom_build.rs:481:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/core/compiler/custom_build.rs:48:56 clippy::doc_markdown "you should put `RunCustomBuild` between ticks in the documentation" cargo-0.49.0/src/cargo/core/compiler/custom_build.rs:561:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/core/compiler/custom_build.rs:561:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/core/compiler/custom_build.rs:567:20 clippy::redundant_closure_for_method_calls "redundant closure found" cargo-0.49.0/src/cargo/core/compiler/custom_build.rs:576:28 clippy::shadow_unrelated "`mut value` is being shadowed" cargo-0.49.0/src/cargo/core/compiler/custom_build.rs:606:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" @@ -255,6 +265,7 @@ cargo-0.49.0/src/cargo/core/compiler/standard_lib.rs:134:1 clippy::missing_error cargo-0.49.0/src/cargo/core/compiler/standard_lib.rs:16:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/compiler/standard_lib.rs:30:28 clippy::redundant_closure_for_method_calls "redundant closure found" cargo-0.49.0/src/cargo/core/compiler/standard_lib.rs:34:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/core/compiler/standard_lib.rs:34:1 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/core/compiler/timings.rs:16:1 clippy::struct_excessive_bools "more than 3 bools in a struct" cargo-0.49.0/src/cargo/core/compiler/timings.rs:192:64 clippy::needless_pass_by_value "this argument is passed by value, but not consumed in the function body" cargo-0.49.0/src/cargo/core/compiler/timings.rs:212:58 clippy::needless_pass_by_value "this argument is passed by value, but not consumed in the function body" @@ -279,6 +290,7 @@ cargo-0.49.0/src/cargo/core/compiler/unit_graph.rs:65:1 clippy::missing_errors_d cargo-0.49.0/src/cargo/core/compiler/unit_graph.rs:65:1 clippy::module_name_repetitions "item name ends with its containing module's name" cargo-0.49.0/src/cargo/core/dependency.rs:157:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/core/dependency.rs:182:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/core/dependency.rs:203:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/core/dependency.rs:203:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/dependency.rs:224:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/dependency.rs:23:1 clippy::struct_excessive_bools "more than 3 bools in a struct" @@ -288,10 +300,13 @@ cargo-0.49.0/src/cargo/core/dependency.rs:274:5 clippy::must_use_candidate "this cargo-0.49.0/src/cargo/core/dependency.rs:278:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/dependency.rs:287:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/dependency.rs:291:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" +cargo-0.49.0/src/cargo/core/dependency.rs:296:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/core/dependency.rs:305:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/dependency.rs:311:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/dependency.rs:319:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" +cargo-0.49.0/src/cargo/core/dependency.rs:323:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/core/dependency.rs:337:75 clippy::redundant_closure_for_method_calls "redundant closure found" +cargo-0.49.0/src/cargo/core/dependency.rs:379:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/core/dependency.rs:397:56 clippy::redundant_closure_for_method_calls "redundant closure found" cargo-0.49.0/src/cargo/core/dependency.rs:403:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/dependency.rs:408:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" @@ -419,6 +434,7 @@ cargo-0.49.0/src/cargo/core/package.rs:174:5 clippy::must_use_candidate "this me cargo-0.49.0/src/cargo/core/package.rs:182:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/package.rs:186:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/package.rs:190:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" +cargo-0.49.0/src/cargo/core/package.rs:194:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/core/package.rs:194:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/package.rs:198:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/package.rs:202:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" @@ -436,10 +452,12 @@ cargo-0.49.0/src/cargo/core/package.rs:287:1 clippy::module_name_repetitions "it cargo-0.49.0/src/cargo/core/package.rs:385:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/core/package.rs:421:5 clippy::needless_lifetimes "explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)" cargo-0.49.0/src/cargo/core/package.rs:425:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/core/package.rs:425:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/core/package.rs:452:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/core/package.rs:453:60 clippy::redundant_closure_for_method_calls "redundant closure found" cargo-0.49.0/src/cargo/core/package.rs:459:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/core/package.rs:473:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/core/package.rs:552:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/core/package.rs:587:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/core/package.rs:588:9 clippy::needless_question_mark "Question mark operator is useless here" cargo-0.49.0/src/cargo/core/package.rs:682:46 clippy::cast_possible_truncation "casting `f64` to `u64` may truncate the value" @@ -450,6 +468,7 @@ cargo-0.49.0/src/cargo/core/package.rs:731:5 clippy::missing_errors_doc "docs fo cargo-0.49.0/src/cargo/core/package.rs:790:13 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`" cargo-0.49.0/src/cargo/core/package.rs:988:9 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`" cargo-0.49.0/src/cargo/core/package_id.rs:115:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/core/package_id.rs:124:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/core/package_id.rs:124:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/package_id.rs:139:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/package_id.rs:142:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" @@ -468,14 +487,17 @@ cargo-0.49.0/src/cargo/core/package_id_spec.rs:179:5 clippy::missing_errors_doc cargo-0.49.0/src/cargo/core/package_id_spec.rs:212:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope" cargo-0.49.0/src/cargo/core/package_id_spec.rs:231:9 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`" cargo-0.49.0/src/cargo/core/package_id_spec.rs:51:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/core/package_id_spec.rs:51:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/core/package_id_spec.rs:77:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/core/package_id_spec.rs:88:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" +cargo-0.49.0/src/cargo/core/profiles.rs:1004:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/core/profiles.rs:1004:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/profiles.rs:1014:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/profiles.rs:1018:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/profiles.rs:1028:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/profiles.rs:106:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope" cargo-0.49.0/src/cargo/core/profiles.rs:143:5 clippy::unnecessary_wraps "this function's return value is unnecessarily wrapped by `Result`" +cargo-0.49.0/src/cargo/core/profiles.rs:286:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/core/profiles.rs:286:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/profiles.rs:294:40 clippy::if_not_else "unnecessary boolean `not` operation" cargo-0.49.0/src/cargo/core/profiles.rs:30:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" @@ -483,6 +505,7 @@ cargo-0.49.0/src/cargo/core/profiles.rs:342:25 clippy::shadow_unrelated "`maker` cargo-0.49.0/src/cargo/core/profiles.rs:370:41 clippy::unused_self "unused `self` argument" cargo-0.49.0/src/cargo/core/profiles.rs:370:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/profiles.rs:372:9 clippy::field_reassign_with_default "field assignment outside of initializer for an instance created with Default::default()" +cargo-0.49.0/src/cargo/core/profiles.rs:382:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/core/profiles.rs:382:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/profiles.rs:383:28 clippy::if_not_else "unnecessary boolean `not` operation" cargo-0.49.0/src/cargo/core/profiles.rs:397:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" @@ -499,7 +522,9 @@ cargo-0.49.0/src/cargo/core/registry.rs:19:5 clippy::missing_errors_doc "docs fo cargo-0.49.0/src/cargo/core/registry.rs:240:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/core/registry.rs:26:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/core/registry.rs:344:49 clippy::redundant_closure_for_method_calls "redundant closure found" +cargo-0.49.0/src/cargo/core/registry.rs:358:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/core/registry.rs:369:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" +cargo-0.49.0/src/cargo/core/registry.rs:424:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/core/registry.rs:424:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/registry.rs:49:1 clippy::module_name_repetitions "item name ends with its containing module's name" cargo-0.49.0/src/cargo/core/registry.rs:520:17 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`" @@ -513,6 +538,7 @@ cargo-0.49.0/src/cargo/core/resolver/context.rs:274:53 clippy::redundant_closure cargo-0.49.0/src/cargo/core/resolver/context.rs:42:1 clippy::module_name_repetitions "item name starts with its containing module's name" cargo-0.49.0/src/cargo/core/resolver/context.rs:74:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/resolver/encode.rs:156:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/core/resolver/encode.rs:156:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/core/resolver/encode.rs:156:5 clippy::too_many_lines "this function has too many lines (164/100)" cargo-0.49.0/src/cargo/core/resolver/encode.rs:339:17 clippy::match_wildcard_for_single_variants "wildcard match will miss any future added variants" cargo-0.49.0/src/cargo/core/resolver/encode.rs:438:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope" @@ -570,6 +596,7 @@ cargo-0.49.0/src/cargo/core/resolver/resolve.rs:255:5 clippy::must_use_candidate cargo-0.49.0/src/cargo/core/resolver/resolve.rs:259:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/resolver/resolve.rs:263:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/resolver/resolve.rs:269:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" +cargo-0.49.0/src/cargo/core/resolver/resolve.rs:273:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/core/resolver/resolve.rs:273:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/resolver/resolve.rs:274:9 clippy::map_unwrap_or "called `map().unwrap_or_else()` on an `Option` value. This can be done more directly by calling `map_or_else(, )` instead" cargo-0.49.0/src/cargo/core/resolver/resolve.rs:280:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" @@ -611,6 +638,7 @@ cargo-0.49.0/src/cargo/core/shell.rs:282:5 clippy::missing_errors_doc "docs for cargo-0.49.0/src/cargo/core/shell.rs:314:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/shell.rs:322:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/shell.rs:330:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/core/shell.rs:345:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/core/shell.rs:98:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/source/mod.rs:103:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/core/source/mod.rs:247:1 clippy::module_name_repetitions "item name starts with its containing module's name" @@ -630,6 +658,7 @@ cargo-0.49.0/src/cargo/core/source/mod.rs:63:5 clippy::missing_errors_doc "docs cargo-0.49.0/src/cargo/core/source/mod.rs:74:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/core/source/mod.rs:83:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/core/source/source_id.rs:107:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/core/source/source_id.rs:107:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/core/source/source_id.rs:128:50 clippy::redundant_closure_for_method_calls "redundant closure found" cargo-0.49.0/src/cargo/core/source/source_id.rs:147:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/source/source_id.rs:156:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" @@ -640,6 +669,7 @@ cargo-0.49.0/src/cargo/core/source/source_id.rs:171:19 clippy::doc_markdown "you cargo-0.49.0/src/cargo/core/source/source_id.rs:172:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/core/source/source_id.rs:178:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/core/source/source_id.rs:187:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/core/source/source_id.rs:187:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/core/source/source_id.rs:18:74 clippy::default_trait_access "calling `std::sync::Mutex::default()` is more clear than this expression" cargo-0.49.0/src/cargo/core/source/source_id.rs:195:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/core/source/source_id.rs:207:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" @@ -652,10 +682,12 @@ cargo-0.49.0/src/cargo/core/source/source_id.rs:241:5 clippy::must_use_candidate cargo-0.49.0/src/cargo/core/source/source_id.rs:252:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/source/source_id.rs:257:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/source/source_id.rs:262:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/core/source/source_id.rs:262:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/core/source/source_id.rs:305:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/source/source_id.rs:310:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/source/source_id.rs:318:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/source/source_id.rs:326:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" +cargo-0.49.0/src/cargo/core/source/source_id.rs:338:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/core/source/source_id.rs:355:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/core/source/source_id.rs:393:61 clippy::match_same_arms "this `match` has identical arm bodies" cargo-0.49.0/src/cargo/core/source/source_id.rs:394:42 clippy::match_same_arms "this `match` has identical arm bodies" @@ -730,8 +762,10 @@ cargo-0.49.0/src/cargo/core/workspace.rs:150:5 clippy::missing_errors_doc "docs cargo-0.49.0/src/cargo/core/workspace.rs:159:16 clippy::redundant_else "redundant else block" cargo-0.49.0/src/cargo/core/workspace.rs:197:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/core/workspace.rs:225:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/core/workspace.rs:225:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/core/workspace.rs:255:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/core/workspace.rs:267:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/core/workspace.rs:317:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/core/workspace.rs:329:37 clippy::doc_markdown "you should put `VirtualManifest` between ticks in the documentation" cargo-0.49.0/src/cargo/core/workspace.rs:410:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/core/workspace.rs:440:9 clippy::unnecessary_wraps "this function's return value is unnecessarily wrapped by `Result`" @@ -742,9 +776,12 @@ cargo-0.49.0/src/cargo/core/workspace.rs:615:22 clippy::redundant_closure_for_me cargo-0.49.0/src/cargo/core/workspace.rs:762:27 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`" cargo-0.49.0/src/cargo/core/workspace.rs:784:17 clippy::if_not_else "unnecessary boolean `not` operation" cargo-0.49.0/src/cargo/core/workspace.rs:849:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/core/workspace.rs:849:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/core/workspace.rs:893:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/core/workspace.rs:906:24 clippy::redundant_else "redundant else block" cargo-0.49.0/src/cargo/core/workspace.rs:932:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/core/workspace.rs:932:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" +cargo-0.49.0/src/cargo/lib.rs:177:1 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/lib.rs:177:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/lib.rs:180:36 clippy::redundant_closure_for_method_calls "redundant closure found" cargo-0.49.0/src/cargo/lib.rs:180:36 clippy::redundant_closure_for_method_calls "redundant closure found" @@ -771,6 +808,7 @@ cargo-0.49.0/src/cargo/ops/cargo_compile.rs:249:1 clippy::missing_errors_doc "do cargo-0.49.0/src/cargo/ops/cargo_compile.rs:258:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/ops/cargo_compile.rs:267:16 clippy::needless_question_mark "Question mark operator is useless here" cargo-0.49.0/src/cargo/ops/cargo_compile.rs:275:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/ops/cargo_compile.rs:275:1 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/ops/cargo_compile.rs:275:1 clippy::too_many_lines "this function has too many lines (219/100)" cargo-0.49.0/src/cargo/ops/cargo_compile.rs:468:9 clippy::default_trait_access "calling `std::collections::HashMap::default()` is more clear than this expression" cargo-0.49.0/src/cargo/ops/cargo_compile.rs:548:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" @@ -786,6 +824,7 @@ cargo-0.49.0/src/cargo/ops/cargo_compile.rs:612:21 clippy::doc_markdown "you sho cargo-0.49.0/src/cargo/ops/cargo_compile.rs:613:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/ops/cargo_compile.rs:618:9 clippy::similar_names "binding's name is too similar to existing binding" cargo-0.49.0/src/cargo/ops/cargo_compile.rs:641:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" +cargo-0.49.0/src/cargo/ops/cargo_compile.rs:652:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/ops/cargo_compile.rs:652:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/ops/cargo_compile.rs:655:50 clippy::match_same_arms "this `match` has identical arm bodies" cargo-0.49.0/src/cargo/ops/cargo_compile.rs:673:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" @@ -801,6 +840,7 @@ cargo-0.49.0/src/cargo/ops/cargo_generate_lockfile.rs:160:5 clippy::items_after_ cargo-0.49.0/src/cargo/ops/cargo_generate_lockfile.rs:175:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope" cargo-0.49.0/src/cargo/ops/cargo_generate_lockfile.rs:22:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/ops/cargo_generate_lockfile.rs:37:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/ops/cargo_generate_lockfile.rs:37:1 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/ops/cargo_generate_lockfile.rs:37:1 clippy::too_many_lines "this function has too many lines (171/100)" cargo-0.49.0/src/cargo/ops/cargo_install.rs:13:5 clippy::wildcard_imports "usage of wildcard import" cargo-0.49.0/src/cargo/ops/cargo_install.rs:148:1 clippy::fn_params_excessive_bools "more than 3 bools in function parameters" @@ -815,6 +855,7 @@ cargo-0.49.0/src/cargo/ops/cargo_install.rs:37:1 clippy::missing_errors_doc "doc cargo-0.49.0/src/cargo/ops/cargo_install.rs:454:22 clippy::redundant_closure_for_method_calls "redundant closure found" cargo-0.49.0/src/cargo/ops/cargo_install.rs:483:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope" cargo-0.49.0/src/cargo/ops/cargo_install.rs:683:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/ops/cargo_install.rs:708:5 clippy::manual_flatten "unnecessary `if let` since only the `Some` variant of the iterator element is used" cargo-0.49.0/src/cargo/ops/cargo_new.rs:101:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/ops/cargo_new.rs:245:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope" cargo-0.49.0/src/cargo/ops/cargo_new.rs:251:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope" @@ -843,6 +884,7 @@ cargo-0.49.0/src/cargo/ops/cargo_pkgid.rs:5:1 clippy::missing_errors_doc "docs f cargo-0.49.0/src/cargo/ops/cargo_read_manifest.rs:14:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/ops/cargo_read_manifest.rs:171:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope" cargo-0.49.0/src/cargo/ops/cargo_read_manifest.rs:37:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/ops/cargo_read_manifest.rs:37:1 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/ops/cargo_read_manifest.rs:57:49 clippy::redundant_closure_for_method_calls "redundant closure found" cargo-0.49.0/src/cargo/ops/cargo_read_manifest.rs:69:37 clippy::redundant_closure_for_method_calls "redundant closure found" cargo-0.49.0/src/cargo/ops/cargo_run.rs:25:24 clippy::if_not_else "unnecessary boolean `not` operation" @@ -851,6 +893,7 @@ cargo-0.49.0/src/cargo/ops/cargo_run.rs:37:16 clippy::redundant_else "redundant cargo-0.49.0/src/cargo/ops/cargo_run.rs:53:9 clippy::if_not_else "unnecessary boolean `not` operation" cargo-0.49.0/src/cargo/ops/cargo_run.rs:65:16 clippy::redundant_else "redundant else block" cargo-0.49.0/src/cargo/ops/cargo_run.rs:9:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/ops/cargo_run.rs:9:1 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/ops/cargo_test.rs:16:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/ops/cargo_test.rs:43:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/ops/cargo_test.rs:84:17 clippy::similar_names "binding's name is too similar to existing binding" @@ -909,6 +952,7 @@ cargo-0.49.0/src/cargo/ops/registry.rs:505:38 clippy::default_trait_access "call cargo-0.49.0/src/cargo/ops/registry.rs:510:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/ops/registry.rs:529:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope" cargo-0.49.0/src/cargo/ops/registry.rs:53:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/ops/registry.rs:53:1 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/ops/registry.rs:573:22 clippy::match_same_arms "this `match` has identical arm bodies" cargo-0.49.0/src/cargo/ops/registry.rs:608:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/ops/registry.rs:621:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" @@ -923,6 +967,7 @@ cargo-0.49.0/src/cargo/ops/registry.rs:794:16 clippy::single_match_else "you see cargo-0.49.0/src/cargo/ops/registry.rs:828:14 clippy::doc_markdown "you should put `SourceId` between ticks in the documentation" cargo-0.49.0/src/cargo/ops/registry.rs:848:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/ops/resolve.rs:199:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/ops/resolve.rs:199:1 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/ops/resolve.rs:199:1 clippy::module_name_repetitions "item name starts with its containing module's name" cargo-0.49.0/src/cargo/ops/resolve.rs:199:1 clippy::too_many_lines "this function has too many lines (137/100)" cargo-0.49.0/src/cargo/ops/resolve.rs:241:28 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`" @@ -953,6 +998,7 @@ cargo-0.49.0/src/cargo/ops/tree/mod.rs:360:30 clippy::match_same_arms "this `mat cargo-0.49.0/src/cargo/ops/tree/mod.rs:58:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/ops/vendor.rs:14:1 clippy::module_name_repetitions "item name starts with its containing module's name" cargo-0.49.0/src/cargo/ops/vendor.rs:21:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/ops/vendor.rs:21:1 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/ops/vendor.rs:314:34 clippy::match_same_arms "this `match` has identical arm bodies" cargo-0.49.0/src/cargo/ops/vendor.rs:320:29 clippy::case_sensitive_file_extension_comparisons "case-sensitive file extension comparison" cargo-0.49.0/src/cargo/ops/vendor.rs:320:60 clippy::case_sensitive_file_extension_comparisons "case-sensitive file extension comparison" @@ -971,8 +1017,10 @@ cargo-0.49.0/src/cargo/sources/directory.rs:14:1 clippy::module_name_repetitions cargo-0.49.0/src/cargo/sources/directory.rs:90:56 clippy::redundant_closure_for_method_calls "redundant closure found" cargo-0.49.0/src/cargo/sources/git/source.rs:14:1 clippy::module_name_repetitions "item name ends with its containing module's name" cargo-0.49.0/src/cargo/sources/git/source.rs:25:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/sources/git/source.rs:25:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/sources/git/source.rs:49:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/sources/git/source.rs:53:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/sources/git/source.rs:53:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/sources/git/source.rs:69:20 clippy::comparison_to_empty "comparison to empty slice" cargo-0.49.0/src/cargo/sources/git/utils.rs:1025:19 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`" cargo-0.49.0/src/cargo/sources/git/utils.rs:1157:36 clippy::case_sensitive_file_extension_comparisons "case-sensitive file extension comparison" @@ -984,6 +1032,7 @@ cargo-0.49.0/src/cargo/sources/git/utils.rs:184:5 clippy::missing_errors_doc "do cargo-0.49.0/src/cargo/sources/git/utils.rs:188:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/sources/git/utils.rs:242:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/sources/git/utils.rs:253:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/sources/git/utils.rs:253:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/sources/git/utils.rs:262:13 clippy::if_not_else "unnecessary boolean `not` operation" cargo-0.49.0/src/cargo/sources/git/utils.rs:289:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/sources/git/utils.rs:294:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" @@ -1013,6 +1062,7 @@ cargo-0.49.0/src/cargo/sources/path.rs:429:5 clippy::missing_errors_doc "docs fo cargo-0.49.0/src/cargo/sources/path.rs:460:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/sources/path.rs:473:43 clippy::redundant_closure_for_method_calls "redundant closure found" cargo-0.49.0/src/cargo/sources/path.rs:482:43 clippy::redundant_closure_for_method_calls "redundant closure found" +cargo-0.49.0/src/cargo/sources/path.rs:55:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/sources/path.rs:63:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/sources/path.rs:77:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/sources/path.rs:98:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" @@ -1046,6 +1096,7 @@ cargo-0.49.0/src/cargo/sources/registry/remote.rs:72:13 clippy::single_match_els cargo-0.49.0/src/cargo/sources/replaced.rs:12:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/sources/replaced.rs:5:1 clippy::module_name_repetitions "item name starts with its containing module's name" cargo-0.49.0/src/cargo/util/canonical_url.rs:19:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/util/canonical_url.rs:19:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/util/canonical_url.rs:50:41 clippy::case_sensitive_file_extension_comparisons "case-sensitive file extension comparison" cargo-0.49.0/src/cargo/util/canonical_url.rs:65:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/util/command_prelude.rs:218:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute" @@ -1091,6 +1142,7 @@ cargo-0.49.0/src/cargo/util/config/mod.rs:100:71 clippy::doc_markdown "you shoul cargo-0.49.0/src/cargo/util/config/mod.rs:1049:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/util/config/mod.rs:1064:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/util/config/mod.rs:1090:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/util/config/mod.rs:1090:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/util/config/mod.rs:1166:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/util/config/mod.rs:1179:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/util/config/mod.rs:1181:33 clippy::needless_question_mark "Question mark operator is useless here" @@ -1105,6 +1157,7 @@ cargo-0.49.0/src/cargo/util/config/mod.rs:1225:5 clippy::missing_errors_doc "doc cargo-0.49.0/src/cargo/util/config/mod.rs:1229:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/util/config/mod.rs:124:1 clippy::struct_excessive_bools "more than 3 bools in a struct" cargo-0.49.0/src/cargo/util/config/mod.rs:1254:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/util/config/mod.rs:1263:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/util/config/mod.rs:1279:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/util/config/mod.rs:1281:9 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`" cargo-0.49.0/src/cargo/util/config/mod.rs:1323:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope" @@ -1120,6 +1173,7 @@ cargo-0.49.0/src/cargo/util/config/mod.rs:1588:5 clippy::must_use_candidate "thi cargo-0.49.0/src/cargo/util/config/mod.rs:1598:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/util/config/mod.rs:1619:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/util/config/mod.rs:1623:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/util/config/mod.rs:1623:1 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/util/config/mod.rs:1623:64 clippy::needless_pass_by_value "this argument is passed by value, but not consumed in the function body" cargo-0.49.0/src/cargo/util/config/mod.rs:1649:9 clippy::option_if_let_else "use Option::map_or_else instead of an if let/else" cargo-0.49.0/src/cargo/util/config/mod.rs:1699:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope" @@ -1151,14 +1205,13 @@ cargo-0.49.0/src/cargo/util/config/mod.rs:699:5 clippy::fn_params_excessive_bool cargo-0.49.0/src/cargo/util/config/mod.rs:699:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/util/config/mod.rs:719:58 clippy::redundant_closure_for_method_calls "redundant closure found" cargo-0.49.0/src/cargo/util/config/mod.rs:816:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" -cargo-0.49.0/src/cargo/util/config/mod.rs:875:36 clippy::similar_names "binding's name is too similar to existing binding" -cargo-0.49.0/src/cargo/util/config/mod.rs:876:37 clippy::similar_names "binding's name is too similar to existing binding" cargo-0.49.0/src/cargo/util/config/path.rs:10:1 clippy::module_name_repetitions "item name ends with its containing module's name" cargo-0.49.0/src/cargo/util/config/path.rs:14:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/util/config/path.rs:48:1 clippy::module_name_repetitions "item name starts with its containing module's name" cargo-0.49.0/src/cargo/util/config/target.rs:12:1 clippy::module_name_repetitions "item name starts with its containing module's name" cargo-0.49.0/src/cargo/util/config/target.rs:24:1 clippy::module_name_repetitions "item name starts with its containing module's name" cargo-0.49.0/src/cargo/util/config/value.rs:29:1 clippy::module_name_repetitions "item name ends with its containing module's name" +cargo-0.49.0/src/cargo/util/config/value.rs:70:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/util/config/value.rs:80:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/util/config/value.rs:81:9 clippy::match_like_matches_macro "match expression looks like `matches!` macro" cargo-0.49.0/src/cargo/util/cpu.rs:11:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" @@ -1166,9 +1219,12 @@ cargo-0.49.0/src/cargo/util/cpu.rs:22:5 clippy::must_use_candidate "this method cargo-0.49.0/src/cargo/util/cpu.rs:82:25 clippy::cast_precision_loss "casting `u64` to `f64` causes a loss of precision (`u64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)" cargo-0.49.0/src/cargo/util/cpu.rs:82:9 clippy::cast_precision_loss "casting `u64` to `f64` causes a loss of precision (`u64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)" cargo-0.49.0/src/cargo/util/dependency_queue.rs:109:27 clippy::redundant_closure_for_method_calls "redundant closure found" +cargo-0.49.0/src/cargo/util/dependency_queue.rs:125:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/util/dependency_queue.rs:151:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/util/dependency_queue.rs:156:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" +cargo-0.49.0/src/cargo/util/dependency_queue.rs:168:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/util/dependency_queue.rs:46:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" +cargo-0.49.0/src/cargo/util/dependency_queue.rs:66:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/util/dependency_queue.rs:91:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope" cargo-0.49.0/src/cargo/util/diagnostic_server.rs:218:1 clippy::module_name_repetitions "item name ends with its containing module's name" cargo-0.49.0/src/cargo/util/diagnostic_server.rs:230:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" @@ -1182,6 +1238,7 @@ cargo-0.49.0/src/cargo/util/errors.rs:143:5 clippy::must_use_candidate "this met cargo-0.49.0/src/cargo/util/errors.rs:150:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/util/errors.rs:15:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/util/errors.rs:237:5 clippy::pub_enum_variant_names "variant name ends with the enum's name" +cargo-0.49.0/src/cargo/util/errors.rs:245:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/util/errors.rs:245:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/util/errors.rs:321:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/util/errors.rs:328:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" @@ -1199,15 +1256,19 @@ cargo-0.49.0/src/cargo/util/flock.rs:150:5 clippy::missing_errors_doc "docs for cargo-0.49.0/src/cargo/util/flock.rs:156:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/util/flock.rs:170:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/util/flock.rs:192:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/util/flock.rs:29:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/util/flock.rs:29:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/util/flock.rs:321:5 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope" cargo-0.49.0/src/cargo/util/flock.rs:335:23 clippy::cast_possible_truncation "casting `i64` to `u32` may truncate the value" cargo-0.49.0/src/cargo/util/flock.rs:335:23 clippy::cast_sign_loss "casting `i64` to `u32` may lose the sign of the value" cargo-0.49.0/src/cargo/util/flock.rs:335:44 clippy::cast_possible_truncation "casting `i64` to `u32` may truncate the value" cargo-0.49.0/src/cargo/util/flock.rs:379:35 clippy::match_same_arms "this `match` has identical arm bodies" +cargo-0.49.0/src/cargo/util/flock.rs:37:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/util/flock.rs:37:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" +cargo-0.49.0/src/cargo/util/flock.rs:43:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/util/flock.rs:43:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/util/flock.rs:52:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/util/flock.rs:52:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/util/graph.rs:10:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/util/graph.rs:41:51 clippy::redundant_closure_for_method_calls "redundant closure found" cargo-0.49.0/src/cargo/util/graph.rs:45:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" @@ -1226,6 +1287,7 @@ cargo-0.49.0/src/cargo/util/hex.rs:8:9 clippy::cast_possible_truncation "casting cargo-0.49.0/src/cargo/util/hex.rs:9:9 clippy::cast_possible_truncation "casting `u64` to `u8` may truncate the value" cargo-0.49.0/src/cargo/util/important_paths.rs:23:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/util/important_paths.rs:6:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/util/interning.rs:66:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/util/interning.rs:66:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/util/interning.rs:77:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/util/into_url.rs:10:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" @@ -1268,7 +1330,9 @@ cargo-0.49.0/src/cargo/util/paths.rs:415:1 clippy::missing_errors_doc "docs for cargo-0.49.0/src/cargo/util/paths.rs:445:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/util/paths.rs:459:45 clippy::redundant_closure_for_method_calls "redundant closure found" cargo-0.49.0/src/cargo/util/paths.rs:469:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/util/paths.rs:469:1 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/util/paths.rs:54:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute" +cargo-0.49.0/src/cargo/util/paths.rs:61:1 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/util/paths.rs:61:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/util/paths.rs:63:19 clippy::option_if_let_else "use Option::map_or_else instead of an if let/else" cargo-0.49.0/src/cargo/util/paths.rs:88:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" @@ -1281,6 +1345,7 @@ cargo-0.49.0/src/cargo/util/process_builder.rs:152:5 clippy::missing_errors_doc cargo-0.49.0/src/cargo/util/process_builder.rs:185:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/util/process_builder.rs:190:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/util/process_builder.rs:218:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/util/process_builder.rs:218:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/util/process_builder.rs:307:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/util/process_builder.rs:343:39 clippy::needless_pass_by_value "this argument is passed by value, but not consumed in the function body" cargo-0.49.0/src/cargo/util/progress.rs:122:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" @@ -1300,16 +1365,22 @@ cargo-0.49.0/src/cargo/util/progress.rs:282:9 clippy::single_char_add_str "calli cargo-0.49.0/src/cargo/util/progress.rs:89:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/util/progress.rs:97:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/util/queue.rs:25:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" +cargo-0.49.0/src/cargo/util/queue.rs:36:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" +cargo-0.49.0/src/cargo/util/queue.rs:42:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" +cargo-0.49.0/src/cargo/util/queue.rs:52:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" +cargo-0.49.0/src/cargo/util/queue.rs:69:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/util/read2.rs:11:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/util/read2.rs:31:17 clippy::similar_names "binding's name is too similar to existing binding" cargo-0.49.0/src/cargo/util/restricted_names.rs:13:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/util/restricted_names.rs:26:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/util/restricted_names.rs:35:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/util/restricted_names.rs:45:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/util/restricted_names.rs:87:1 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/util/restricted_names.rs:87:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/util/restricted_names.rs:89:21 clippy::redundant_closure_for_method_calls "redundant closure found" cargo-0.49.0/src/cargo/util/restricted_names.rs:8:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute" cargo-0.49.0/src/cargo/util/rustc.rs:103:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/util/rustc.rs:103:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/util/rustc.rs:114:5 clippy::doc_markdown "you should put bare URLs between `<`/`>` or make a proper Markdown link" cargo-0.49.0/src/cargo/util/rustc.rs:115:5 clippy::doc_markdown "you should put bare URLs between `<`/`>` or make a proper Markdown link" cargo-0.49.0/src/cargo/util/rustc.rs:162:17 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope" @@ -1349,6 +1420,7 @@ cargo-0.49.0/src/cargo/util/toml/mod.rs:824:1 clippy::module_name_repetitions "i cargo-0.49.0/src/cargo/util/toml/mod.rs:834:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" cargo-0.49.0/src/cargo/util/toml/mod.rs:83:42 clippy::redundant_closure_for_method_calls "redundant closure found" cargo-0.49.0/src/cargo/util/toml/mod.rs:852:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +cargo-0.49.0/src/cargo/util/toml/mod.rs:852:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" cargo-0.49.0/src/cargo/util/toml/mod.rs:852:5 clippy::too_many_lines "this function has too many lines (138/100)" cargo-0.49.0/src/cargo/util/toml/mod.rs:962:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope" cargo-0.49.0/src/cargo/util/toml/mod.rs:979:9 clippy::items_after_statements "adding items after statements is confusing, since items exist from the start of the scope" @@ -1394,6 +1466,7 @@ iron-0.6.1/src/middleware/mod.rs:173:5 clippy::missing_errors_doc "docs for func iron-0.6.1/src/middleware/mod.rs:182:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" iron-0.6.1/src/middleware/mod.rs:192:1 clippy::module_name_repetitions "item name ends with its containing module's name" iron-0.6.1/src/middleware/mod.rs:217:25 clippy::doc_markdown "you should put `ChainBuilder` between ticks in the documentation" +iron-0.6.1/src/middleware/mod.rs:264:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" iron-0.6.1/src/middleware/mod.rs:328:20 clippy::similar_names "binding's name is too similar to existing binding" iron-0.6.1/src/middleware/mod.rs:360:16 clippy::similar_names "binding's name is too similar to existing binding" iron-0.6.1/src/middleware/mod.rs:368:33 clippy::similar_names "binding's name is too similar to existing binding" @@ -1424,8 +1497,11 @@ iron-0.6.1/src/request/url.rs:22:5 clippy::missing_errors_doc "docs for function iron-0.6.1/src/request/url.rs:31:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" iron-0.6.1/src/request/url.rs:47:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" iron-0.6.1/src/request/url.rs:52:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" +iron-0.6.1/src/request/url.rs:57:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" iron-0.6.1/src/request/url.rs:57:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" +iron-0.6.1/src/request/url.rs:63:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" iron-0.6.1/src/request/url.rs:63:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" +iron-0.6.1/src/request/url.rs:73:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" iron-0.6.1/src/request/url.rs:73:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" iron-0.6.1/src/request/url.rs:83:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" iron-0.6.1/src/request/url.rs:96:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" @@ -1915,6 +1991,7 @@ log-0.4.11/src/lib.rs:1118:5 clippy::must_use_candidate "this method could have log-0.4.11/src/lib.rs:1177:1 clippy::inline_always "you have declared `#[inline(always)]` on `max_level`. This is usually a bad idea" log-0.4.11/src/lib.rs:1178:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute" log-0.4.11/src/lib.rs:1306:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +log-0.4.11/src/lib.rs:1306:1 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" log-0.4.11/src/lib.rs:1358:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute" log-0.4.11/src/lib.rs:1359:5 clippy::if_not_else "unnecessary `!=` operation" log-0.4.11/src/lib.rs:1407:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute" @@ -1923,6 +2000,7 @@ log-0.4.11/src/lib.rs:356:1 clippy::expl_impl_clone_on_copy "you are implementin log-0.4.11/src/lib.rs:448:12 clippy::manual_range_contains "manual `RangeInclusive::contains` implementation" log-0.4.11/src/lib.rs:500:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" log-0.4.11/src/lib.rs:506:28 clippy::trivially_copy_pass_by_ref "this argument (8 byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte)" +log-0.4.11/src/lib.rs:506:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" log-0.4.11/src/lib.rs:506:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" log-0.4.11/src/lib.rs:520:27 clippy::derive_hash_xor_eq "you are deriving `Hash` but have implemented `PartialEq` explicitly" log-0.4.11/src/lib.rs:538:1 clippy::expl_impl_clone_on_copy "you are implementing `Clone` explicitly on a `Copy` type" @@ -2009,10 +2087,66 @@ proc-macro2-1.0.24/src/parse.rs:808:15 clippy::explicit_iter_loop "it is more co proc-macro2-1.0.24/src/wrapper.rs:415:24 clippy::trivially_copy_pass_by_ref "this argument (4 byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte)" proc-macro2-1.0.24/src/wrapper.rs:429:23 clippy::trivially_copy_pass_by_ref "this argument (4 byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte)" proc-macro2-1.0.24/src/wrapper.rs:492:17 clippy::trivially_copy_pass_by_ref "this argument (4 byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte)" +puffin-02dd4a3/puffin-imgui/src/ui.rs:158:15 clippy::cast_precision_loss "casting `i64` to `f32` causes a loss of precision (`i64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide)" +puffin-02dd4a3/puffin-imgui/src/ui.rs:175:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" +puffin-02dd4a3/puffin-imgui/src/ui.rs:183:5 clippy::too_many_lines "this function has too many lines (115/100)" +puffin-02dd4a3/puffin-imgui/src/ui.rs:1:5 clippy::wildcard_imports "usage of wildcard import" +puffin-02dd4a3/puffin-imgui/src/ui.rs:207:16 clippy::collapsible_else_if "this `else { if .. }` block can be collapsed" +puffin-02dd4a3/puffin-imgui/src/ui.rs:271:67 clippy::cast_precision_loss "casting `i64` to `f32` causes a loss of precision (`i64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide)" +puffin-02dd4a3/puffin-imgui/src/ui.rs:2:5 clippy::wildcard_imports "usage of wildcard import" +puffin-02dd4a3/puffin-imgui/src/ui.rs:376:29 clippy::cast_precision_loss "casting `i64` to `f32` causes a loss of precision (`i64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide)" +puffin-02dd4a3/puffin-imgui/src/ui.rs:381:44 clippy::cast_precision_loss "casting `i64` to `f32` causes a loss of precision (`i64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide)" +puffin-02dd4a3/puffin-imgui/src/ui.rs:453:9 clippy::similar_names "binding's name is too similar to existing binding" +puffin-02dd4a3/puffin-imgui/src/ui.rs:540:14 clippy::cast_possible_truncation "casting `f64` to `f32` may truncate the value" +puffin-02dd4a3/puffin-imgui/src/ui.rs:551:5 clippy::cast_precision_loss "casting `i64` to `f64` causes a loss of precision (`i64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)" +puffin-02dd4a3/puffin-imgui/src/ui.rs:584:39 clippy::cast_precision_loss "casting `usize` to `f32` causes a loss of precision (`usize` is 32 or 64 bits wide, but `f32`'s mantissa is only 23 bits wide)" +puffin-02dd4a3/puffin-imgui/src/ui.rs:59:26 clippy::unsafe_derive_deserialize "you are deriving `serde::Deserialize` on a type that has methods using `unsafe`" +puffin-02dd4a3/puffin-imgui/src/ui.rs:61:1 clippy::module_name_repetitions "item name ends with its containing module's name" +puffin-02dd4a3/puffin-imgui/src/ui.rs:627:39 clippy::cast_precision_loss "casting `usize` to `f32` causes a loss of precision (`usize` is 32 or 64 bits wide, but `f32`'s mantissa is only 23 bits wide)" +puffin-02dd4a3/puffin-imgui/src/ui.rs:674:47 clippy::cast_precision_loss "casting `usize` to `f64` causes a loss of precision on targets with 64-bit wide pointers (`usize` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)" +puffin-02dd4a3/puffin-imgui/src/ui.rs:690:9 clippy::cast_precision_loss "casting `usize` to `f32` causes a loss of precision (`usize` is 32 or 64 bits wide, but `f32`'s mantissa is only 23 bits wide)" +puffin-02dd4a3/puffin/src/data.rs:102:25 clippy::cast_possible_truncation "casting `usize` to `u8` may truncate the value" +puffin-02dd4a3/puffin/src/data.rs:112:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" +puffin-02dd4a3/puffin/src/data.rs:116:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +puffin-02dd4a3/puffin/src/data.rs:137:24 clippy::match_same_arms "this `match` has identical arm bodies" +puffin-02dd4a3/puffin/src/data.rs:177:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +puffin-02dd4a3/puffin/src/data.rs:211:21 clippy::cast_possible_truncation "casting `u64` to `usize` may truncate the value on targets with 32-bit wide pointers" +puffin-02dd4a3/puffin/src/data.rs:24:5 clippy::wildcard_imports "usage of wildcard import" +puffin-02dd4a3/puffin/src/data.rs:75:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" +puffin-02dd4a3/puffin/src/lib.rs:113:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" +puffin-02dd4a3/puffin/src/lib.rs:147:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +puffin-02dd4a3/puffin/src/lib.rs:147:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" +puffin-02dd4a3/puffin/src/lib.rs:165:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +puffin-02dd4a3/puffin/src/lib.rs:200:21 clippy::default_trait_access "calling `Stream::default()` is more clear than this expression" +puffin-02dd4a3/puffin/src/lib.rs:257:78 clippy::default_trait_access "calling `std::cell::RefCell::default()` is more clear than this expression" +puffin-02dd4a3/puffin/src/lib.rs:297:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" +puffin-02dd4a3/puffin/src/lib.rs:302:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" +puffin-02dd4a3/puffin/src/lib.rs:308:28 clippy::default_trait_access "calling `FullProfileData::default()` is more clear than this expression" +puffin-02dd4a3/puffin/src/lib.rs:316:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute" +puffin-02dd4a3/puffin/src/lib.rs:321:5 clippy::cast_possible_truncation "casting `u128` to `i64` may truncate the value" +puffin-02dd4a3/puffin/src/lib.rs:348:28 clippy::default_trait_access "calling `std::marker::PhantomData::default()` is more clear than this expression" +puffin-02dd4a3/puffin/src/lib.rs:359:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute" +puffin-02dd4a3/puffin/src/lib.rs:375:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute" +puffin-02dd4a3/puffin/src/lib.rs:376:5 clippy::option_if_let_else "use Option::map_or instead of an if let/else" +puffin-02dd4a3/puffin/src/lib.rs:377:9 clippy::option_if_let_else "use Option::map_or instead of an if let/else" +puffin-02dd4a3/puffin/src/lib.rs:406:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute" +puffin-02dd4a3/puffin/src/lib.rs:408:5 clippy::option_if_let_else "use Option::map_or instead of an if let/else" +puffin-02dd4a3/puffin/src/lib.rs:69:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" +puffin-02dd4a3/puffin/src/lib.rs:73:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" +puffin-02dd4a3/puffin/src/lib.rs:77:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" +puffin-02dd4a3/puffin/src/merge.rs:21:1 clippy::module_name_repetitions "item name starts with its containing module's name" +puffin-02dd4a3/puffin/src/merge.rs:28:1 clippy::module_name_repetitions "item name starts with its containing module's name" +puffin-02dd4a3/puffin/src/merge.rs:28:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute" +puffin-02dd4a3/puffin/src/merge.rs:35:1 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +puffin-02dd4a3/puffin/src/merge.rs:35:1 clippy::module_name_repetitions "item name starts with its containing module's name" +puffin-02dd4a3/puffin/src/merge.rs:64:43 clippy::default_trait_access "calling `std::vec::Vec::default()` is more clear than this expression" +puffin-02dd4a3/puffin/src/merge.rs:65:54 clippy::default_trait_access "calling `std::collections::HashMap::default()` is more clear than this expression" +puffin-02dd4a3/puffin/src/merge.rs:9:1 clippy::module_name_repetitions "item name starts with its containing module's name" quote-1.0.7/src/ext.rs:10:1 clippy::module_name_repetitions "item name ends with its containing module's name" quote-1.0.7/src/ext.rs:7:5 clippy::doc_markdown "you should put `TokenStream` between ticks in the documentation" quote-1.0.7/src/ident_fragment.rs:13:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" quote-1.0.7/src/ident_fragment.rs:51:31 clippy::manual_strip "stripping a prefix manually" +quote-1.0.7/src/runtime.rs:332:1 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" quote-1.0.7/src/runtime.rs:52:5 clippy::module_name_repetitions "item name ends with its containing module's name" quote-1.0.7/src/runtime.rs:63:5 clippy::module_name_repetitions "item name ends with its containing module's name" quote-1.0.7/src/runtime.rs:66:33 clippy::doc_markdown "you should put `DoesNotHaveIter` between ticks in the documentation" @@ -2049,6 +2183,7 @@ rand-0.7.3/src/distributions/binomial.rs:233:32 clippy::cast_precision_loss "cas rand-0.7.3/src/distributions/binomial.rs:234:27 clippy::cast_precision_loss "casting `i64` to `f64` causes a loss of precision (`i64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)" rand-0.7.3/src/distributions/binomial.rs:251:22 clippy::cast_sign_loss "casting `i64` to `u64` may lose the sign of the value" rand-0.7.3/src/distributions/binomial.rs:255:9 clippy::if_not_else "unnecessary `!=` operation" +rand-0.7.3/src/distributions/binomial.rs:35:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" rand-0.7.3/src/distributions/binomial.rs:35:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" rand-0.7.3/src/distributions/binomial.rs:45:17 clippy::cast_precision_loss "casting `i64` to `f64` causes a loss of precision (`i64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)" rand-0.7.3/src/distributions/binomial.rs:46:5 clippy::cast_possible_truncation "casting `f64` to `i64` may truncate the value" @@ -2059,18 +2194,25 @@ rand-0.7.3/src/distributions/binomial.rs:81:21 clippy::cast_precision_loss "cast rand-0.7.3/src/distributions/binomial.rs:82:32 clippy::cast_possible_truncation "casting `u64` to `i32` may truncate the value" rand-0.7.3/src/distributions/binomial.rs:88:26 clippy::cast_precision_loss "casting `u64` to `f64` causes a loss of precision (`u64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)" rand-0.7.3/src/distributions/binomial.rs:99:21 clippy::cast_precision_loss "casting `u64` to `f64` causes a loss of precision (`u64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide)" +rand-0.7.3/src/distributions/cauchy.rs:33:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" rand-0.7.3/src/distributions/cauchy.rs:33:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" rand-0.7.3/src/distributions/dirichlet.rs:52:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" rand-0.7.3/src/distributions/dirichlet.rs:64:32 clippy::unseparated_literal_suffix "float type suffix should be separated by an underscore" rand-0.7.3/src/distributions/dirichlet.rs:65:23 clippy::unseparated_literal_suffix "float type suffix should be separated by an underscore" +rand-0.7.3/src/distributions/exponential.rs:76:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" rand-0.7.3/src/distributions/exponential.rs:76:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" rand-0.7.3/src/distributions/float.rs:73:1 clippy::module_name_repetitions "item name ends with its containing module's name" rand-0.7.3/src/distributions/gamma.rs:13:5 clippy::enum_glob_use "usage of wildcard import for enum variants" rand-0.7.3/src/distributions/gamma.rs:14:5 clippy::enum_glob_use "usage of wildcard import for enum variants" +rand-0.7.3/src/distributions/gamma.rs:189:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" rand-0.7.3/src/distributions/gamma.rs:189:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" +rand-0.7.3/src/distributions/gamma.rs:230:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" rand-0.7.3/src/distributions/gamma.rs:230:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" +rand-0.7.3/src/distributions/gamma.rs:259:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" rand-0.7.3/src/distributions/gamma.rs:259:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" +rand-0.7.3/src/distributions/gamma.rs:287:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" rand-0.7.3/src/distributions/gamma.rs:287:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" +rand-0.7.3/src/distributions/gamma.rs:90:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" rand-0.7.3/src/distributions/gamma.rs:90:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" rand-0.7.3/src/distributions/integer.rs:23:9 clippy::cast_possible_truncation "casting `u32` to `u8` may truncate the value" rand-0.7.3/src/distributions/integer.rs:30:9 clippy::cast_possible_truncation "casting `u32` to `u16` may truncate the value" @@ -2084,6 +2226,7 @@ rand-0.7.3/src/distributions/normal.rs:47:25 clippy::unseparated_literal_suffix rand-0.7.3/src/distributions/normal.rs:48:25 clippy::unseparated_literal_suffix "float type suffix should be separated by an underscore" rand-0.7.3/src/distributions/other.rs:89:9 clippy::cast_possible_wrap "casting `u32` to `i32` may wrap around the value" rand-0.7.3/src/distributions/pareto.rs:32:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" +rand-0.7.3/src/distributions/poisson.rs:35:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" rand-0.7.3/src/distributions/poisson.rs:35:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" rand-0.7.3/src/distributions/poisson.rs:87:30 clippy::cast_possible_truncation "casting `f64` to `u64` may truncate the value" rand-0.7.3/src/distributions/poisson.rs:87:30 clippy::cast_sign_loss "casting `f64` to `u64` may lose the sign of the value" @@ -2153,11 +2296,13 @@ rand-0.7.3/src/distributions/weighted/alias_method.rs:259:28 clippy::clone_on_co rand-0.7.3/src/distributions/weighted/alias_method.rs:296:9 clippy::map_clone "you are using an explicit closure for copying elements" rand-0.7.3/src/distributions/weighted/alias_method.rs:321:9 clippy::map_clone "you are using an explicit closure for copying elements" rand-0.7.3/src/distributions/weighted/alias_method.rs:78:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +rand-0.7.3/src/distributions/weighted/alias_method.rs:78:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" rand-0.7.3/src/distributions/weighted/alias_method.rs:78:5 clippy::too_many_lines "this function has too many lines (106/100)" rand-0.7.3/src/distributions/weighted/alias_method.rs:85:17 clippy::cast_possible_truncation "casting `usize` to `u32` may truncate the value on targets with 64-bit wide pointers" rand-0.7.3/src/distributions/weighted/alias_method.rs:87:31 clippy::map_unwrap_or "called `map().unwrap_or()` on an `Option` value. This can be done more directly by calling `map_or(, )` instead" rand-0.7.3/src/distributions/weighted/mod.rs:100:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" rand-0.7.3/src/distributions/weighted/mod.rs:144:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +rand-0.7.3/src/distributions/weighted/mod.rs:144:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" rand-0.7.3/src/distributions/weighted/mod.rs:169:16 clippy::int_plus_one "unnecessary `>= y + 1` or `x - 1 >=`" rand-0.7.3/src/distributions/weighted/mod.rs:386:1 clippy::module_name_repetitions "item name starts with its containing module's name" rand-0.7.3/src/distributions/weighted/mod.rs:85:1 clippy::module_name_repetitions "item name starts with its containing module's name" @@ -2188,6 +2333,7 @@ rand-0.7.3/src/rngs/std.rs:54:5 clippy::inline_always "you have declared `#[inli rand-0.7.3/src/rngs/std.rs:63:5 clippy::inline_always "you have declared `#[inline(always)]` on `from_seed`. This is usually a bad idea" rand-0.7.3/src/rngs/std.rs:68:5 clippy::inline_always "you have declared `#[inline(always)]` on `from_rng`. This is usually a bad idea" rand-0.7.3/src/rngs/thread.rs:57:1 clippy::module_name_repetitions "item name starts with its containing module's name" +rand-0.7.3/src/rngs/thread.rs:80:1 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" rand-0.7.3/src/rngs/thread.rs:80:1 clippy::module_name_repetitions "item name starts with its containing module's name" rand-0.7.3/src/rngs/thread.rs:80:1 clippy::must_use_candidate "this function could have a `#[must_use]` attribute" rand-0.7.3/src/rngs/thread.rs:81:35 clippy::redundant_closure_for_method_calls "redundant closure found" @@ -2198,6 +2344,7 @@ rand-0.7.3/src/seq/index.rs:139:13 clippy::enum_glob_use "usage of wildcard impo rand-0.7.3/src/seq/index.rs:159:1 clippy::module_name_repetitions "item name starts with its containing module's name" rand-0.7.3/src/seq/index.rs:171:13 clippy::enum_glob_use "usage of wildcard import for enum variants" rand-0.7.3/src/seq/index.rs:180:13 clippy::enum_glob_use "usage of wildcard import for enum variants" +rand-0.7.3/src/seq/index.rs:213:1 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" rand-0.7.3/src/seq/index.rs:223:18 clippy::cast_possible_truncation "casting `usize` to `u32` may truncate the value on targets with 64-bit wide pointers" rand-0.7.3/src/seq/index.rs:224:18 clippy::cast_possible_truncation "casting `usize` to `u32` may truncate the value on targets with 64-bit wide pointers" rand-0.7.3/src/seq/index.rs:233:25 clippy::cast_precision_loss "casting `u32` to `f32` causes a loss of precision (`u32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide)" @@ -2222,12 +2369,14 @@ rand-0.7.3/src/seq/mod.rs:45:4 clippy::needless_doctest_main "needless `fn main` rand-0.7.3/src/seq/mod.rs:527:26 clippy::cast_possible_truncation "casting `usize` to `u32` may truncate the value on targets with 64-bit wide pointers" rand_core-0.6.0/src/block.rs:117:1 clippy::module_name_repetitions "item name starts with its containing module's name" rand_core-0.6.0/src/block.rs:153:5 clippy::inline_always "you have declared `#[inline(always)]` on `index`. This is usually a bad idea" +rand_core-0.6.0/src/block.rs:168:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" rand_core-0.6.0/src/block.rs:230:5 clippy::inline_always "you have declared `#[inline(always)]` on `try_fill_bytes`. This is usually a bad idea" rand_core-0.6.0/src/block.rs:240:5 clippy::inline_always "you have declared `#[inline(always)]` on `from_seed`. This is usually a bad idea" rand_core-0.6.0/src/block.rs:245:5 clippy::inline_always "you have declared `#[inline(always)]` on `seed_from_u64`. This is usually a bad idea" rand_core-0.6.0/src/block.rs:250:5 clippy::inline_always "you have declared `#[inline(always)]` on `from_rng`. This is usually a bad idea" rand_core-0.6.0/src/block.rs:280:1 clippy::module_name_repetitions "item name starts with its containing module's name" rand_core-0.6.0/src/block.rs:319:5 clippy::inline_always "you have declared `#[inline(always)]` on `index`. This is usually a bad idea" +rand_core-0.6.0/src/block.rs:335:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" rand_core-0.6.0/src/block.rs:405:5 clippy::inline_always "you have declared `#[inline(always)]` on `try_fill_bytes`. This is usually a bad idea" rand_core-0.6.0/src/block.rs:415:5 clippy::inline_always "you have declared `#[inline(always)]` on `from_seed`. This is usually a bad idea" rand_core-0.6.0/src/block.rs:420:5 clippy::inline_always "you have declared `#[inline(always)]` on `seed_from_u64`. This is usually a bad idea" @@ -2237,6 +2386,8 @@ rand_core-0.6.0/src/block.rs:68:1 clippy::module_name_repetitions "item name sta rand_core-0.6.0/src/error.rs:106:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" rand_core-0.6.0/src/error.rs:87:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" rand_core-0.6.0/src/error.rs:95:74 clippy::cast_possible_wrap "casting `u32` to `i32` may wrap around the value" +rand_core-0.6.0/src/le.rs:18:1 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" +rand_core-0.6.0/src/le.rs:27:1 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" rand_core-0.6.0/src/lib.rs:179:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" rand_core-0.6.0/src/lib.rs:301:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" rand_core-0.6.0/src/lib.rs:303:26 clippy::unreadable_literal "long literal lacking separators" @@ -2548,6 +2699,7 @@ regex-1.3.2/src/compile.rs:1040:38 clippy::cast_possible_truncation "casting `u1 regex-1.3.2/src/compile.rs:1051:25 clippy::unseparated_literal_suffix "integer type suffix should be separated by an underscore" regex-1.3.2/src/compile.rs:1071:8 clippy::cast_lossless "casting `u32` to `u64` may become silently lossy if you later change the type" regex-1.3.2/src/compile.rs:112:5 clippy::missing_errors_doc "docs for function returning `Result` missing `# Errors` section" +regex-1.3.2/src/compile.rs:112:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" regex-1.3.2/src/compile.rs:154:30 clippy::redundant_closure_for_method_calls "redundant closure found" regex-1.3.2/src/compile.rs:156:30 clippy::redundant_closure_for_method_calls "redundant closure found" regex-1.3.2/src/compile.rs:185:5 clippy::unnecessary_wraps "this function's return value is unnecessarily wrapped by `Result`" @@ -2877,6 +3029,7 @@ regex-1.3.2/src/re_bytes.rs:256:13 clippy::redundant_field_names "redundant fiel regex-1.3.2/src/re_bytes.rs:29:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" regex-1.3.2/src/re_bytes.rs:35:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" regex-1.3.2/src/re_bytes.rs:42:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" +regex-1.3.2/src/re_bytes.rs:483:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" regex-1.3.2/src/re_bytes.rs:48:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" regex-1.3.2/src/re_bytes.rs:558:29 clippy::doc_markdown "you should put `shortest_match` between ticks in the documentation" regex-1.3.2/src/re_bytes.rs:55:33 clippy::redundant_field_names "redundant field names in struct initialization" @@ -2917,6 +3070,7 @@ regex-1.3.2/src/re_unicode.rs:313:13 clippy::redundant_field_names "redundant fi regex-1.3.2/src/re_unicode.rs:38:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" regex-1.3.2/src/re_unicode.rs:44:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" regex-1.3.2/src/re_unicode.rs:51:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" +regex-1.3.2/src/re_unicode.rs:533:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" regex-1.3.2/src/re_unicode.rs:57:5 clippy::must_use_candidate "this method could have a `#[must_use]` attribute" regex-1.3.2/src/re_unicode.rs:617:29 clippy::doc_markdown "you should put `shortest_match` between ticks in the documentation" regex-1.3.2/src/re_unicode.rs:631:29 clippy::doc_markdown "you should put `is_match` between ticks in the documentation" @@ -2960,10 +3114,10 @@ regex-1.3.2/src/utf8.rs:85:19 clippy::cast_lossless "casting `u8` to `u32` may b regex-1.3.2/src/utf8.rs:92:23 clippy::unusual_byte_groupings "digits of hex or binary literal not grouped by four" regex-1.3.2/src/utf8.rs:92:9 clippy::unusual_byte_groupings "digits of hex or binary literal not grouped by four" regex-1.3.2/src/utf8.rs:97:16 clippy::unusual_byte_groupings "digits of hex or binary literal not grouped by four" -ripgrep-12.1.1//home/matthias/.rustup/toolchains/nightly-2021-01-15-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/macros.rs:14:27 clippy::match_same_arms "this `match` has identical arm bodies" -ripgrep-12.1.1//home/matthias/.rustup/toolchains/nightly-2021-01-15-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/macros.rs:14:27 clippy::match_same_arms "this `match` has identical arm bodies" -ripgrep-12.1.1//home/matthias/.rustup/toolchains/nightly-2021-01-15-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/macros.rs:14:27 clippy::match_same_arms "this `match` has identical arm bodies" -ripgrep-12.1.1//home/matthias/.rustup/toolchains/nightly-2021-01-15-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/macros.rs:14:27 clippy::match_same_arms "this `match` has identical arm bodies" +ripgrep-12.1.1//home/matthias/.rustup/toolchains/nightly-2021-02-03-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/panic.rs:30:27 clippy::match_same_arms "this `match` has identical arm bodies" +ripgrep-12.1.1//home/matthias/.rustup/toolchains/nightly-2021-02-03-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/panic.rs:30:27 clippy::match_same_arms "this `match` has identical arm bodies" +ripgrep-12.1.1//home/matthias/.rustup/toolchains/nightly-2021-02-03-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/panic.rs:30:27 clippy::match_same_arms "this `match` has identical arm bodies" +ripgrep-12.1.1//home/matthias/.rustup/toolchains/nightly-2021-02-03-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/panic.rs:30:27 clippy::match_same_arms "this `match` has identical arm bodies" ripgrep-12.1.1/build.rs:133:19 clippy::option_as_ref_deref "called `.as_ref().map(|x| &**x)` on an Option value. This can be done more directly by calling `githash.as_deref()` instead" ripgrep-12.1.1/build.rs:18:18 clippy::single_match_else "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`" ripgrep-12.1.1/build.rs:225:14 clippy::redundant_closure_for_method_calls "redundant closure found" @@ -3064,11 +3218,17 @@ ripgrep-12.1.1/crates/core/subject.rs:20:1 clippy::module_name_repetitions "item ripgrep-12.1.1/crates/core/subject.rs:4:1 clippy::single_component_path_imports "this import is redundant" syn-1.0.54/build.rs:1:null clippy::cargo_common_metadata "package `syn` is missing `package.keywords` metadata" syn-1.0.54/build.rs:1:null clippy::multiple_crate_versions "could not read cargo metadata: `cargo metadata` exited with an error: Downloading crates ...\n Downloaded syn-test-suite v0.0.0\nerror: failed to verify the checksum of `syn-test-suite v0.0.0`" +syn-1.0.54/src/generics.rs:174:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" syn-1.0.54/src/lib.rs:1:null clippy::cargo_common_metadata "package `syn` is missing `package.keywords` metadata" syn-1.0.54/src/lib.rs:1:null clippy::multiple_crate_versions "could not read cargo metadata: `cargo metadata` exited with an error: Downloading crates ...\n Downloaded syn-test-suite v0.0.0\nerror: failed to verify the checksum of `syn-test-suite v0.0.0`" syn-1.0.54/src/lit.rs:1397:40 clippy::redundant_else "redundant else block" syn-1.0.54/src/lit.rs:1405:28 clippy::redundant_else "redundant else block" syn-1.0.54/src/lit.rs:1485:32 clippy::redundant_else "redundant else block" +syn-1.0.54/src/lit.rs:343:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" +syn-1.0.54/src/lit.rs:437:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" +syn-1.0.54/src/lit.rs:916:9 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" +syn-1.0.54/src/token.rs:974:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" +syn-1.0.54/src/token.rs:996:5 clippy::missing_panics_doc "docs for function which may panic missing `# Panics` section" unicode-xid-0.2.1/src/lib.rs:1:null clippy::cargo_common_metadata "package `unicode-xid` is missing `package.categories` metadata" unicode-xid-0.2.1/src/lib.rs:56:11 clippy::upper_case_acronyms "name `UnicodeXID` contains a capitalized acronym" unicode-xid-0.2.1/src/lib.rs:57:64 clippy::doc_markdown "you should put `XID_Start` between ticks in the documentation" @@ -3266,6 +3426,7 @@ clippy::explicit_deref_methods 1 clippy::from_iter_instead_of_collect 1 clippy::from_over_into 1 clippy::int_plus_one 1 +clippy::manual_flatten 1 clippy::manual_saturating_arithmetic 1 clippy::mem_replace_with_default 1 clippy::nonminimal_bool 1 @@ -3279,6 +3440,7 @@ clippy::should_implement_trait 1 clippy::stable_sort_primitive 1 clippy::unit_arg 1 clippy::unnecessary_lazy_evaluations 1 +clippy::unsafe_derive_deserialize 1 clippy::used_underscore_binding 1 clippy::verbose_bit_mask 1 clippy::while_let_on_iterator 1 @@ -3306,7 +3468,6 @@ clippy::ptr_arg 3 clippy::zero_ptr 3 clippy::let_underscore_drop 4 clippy::too_many_arguments 4 -clippy::collapsible_else_if 5 clippy::explicit_iter_loop 5 clippy::field_reassign_with_default 5 clippy::identity_op 5 @@ -3315,6 +3476,7 @@ clippy::match_like_matches_macro 5 clippy::needless_return 5 clippy::new_without_default 5 clippy::ptr_as_ptr 5 +clippy::collapsible_else_if 6 clippy::manual_strip 6 clippy::non_ascii_literal 6 clippy::single_component_path_imports 6 @@ -3332,12 +3494,11 @@ clippy::missing_safety_doc 10 clippy::needless_doctest_main 10 clippy::multiple_crate_versions 11 clippy::needless_lifetimes 12 -clippy::option_if_let_else 12 clippy::cargo_common_metadata 13 clippy::shadow_unrelated 13 clippy::linkedlist 14 clippy::single_char_add_str 14 -clippy::default_trait_access 16 +clippy::option_if_let_else 15 clippy::needless_pass_by_value 18 clippy::upper_case_acronyms 18 clippy::cast_possible_wrap 19 @@ -3348,25 +3509,27 @@ clippy::unusual_byte_groupings 19 clippy::map_unwrap_or 20 clippy::struct_excessive_bools 20 clippy::redundant_static_lifetimes 21 +clippy::default_trait_access 22 clippy::cast_lossless 23 clippy::trivially_copy_pass_by_ref 26 clippy::redundant_else 29 -clippy::too_many_lines 31 -clippy::cast_precision_loss 35 +clippy::too_many_lines 32 clippy::if_not_else 35 clippy::enum_glob_use 40 clippy::unseparated_literal_suffix 41 +clippy::cast_precision_loss 44 clippy::single_match_else 45 clippy::inline_always 59 -clippy::match_same_arms 64 -clippy::similar_names 79 -clippy::cast_possible_truncation 91 +clippy::match_same_arms 65 +clippy::similar_names 78 +clippy::cast_possible_truncation 95 +clippy::missing_panics_doc 108 clippy::redundant_field_names 111 clippy::redundant_closure_for_method_calls 135 -clippy::module_name_repetitions 137 clippy::items_after_statements 139 -clippy::wildcard_imports 160 +clippy::module_name_repetitions 142 +clippy::wildcard_imports 163 clippy::doc_markdown 178 -clippy::missing_errors_doc 338 +clippy::missing_errors_doc 343 clippy::unreadable_literal 365 -clippy::must_use_candidate 552 +clippy::must_use_candidate 565 diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain index b617203bef6d8..e73da595e19df 100644 --- a/src/tools/clippy/rust-toolchain +++ b/src/tools/clippy/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2021-02-03" -components = ["llvm-tools-preview", "rustc-dev", "rust-src", "rustfmt"] +channel = "nightly-2021-02-11" +components = ["llvm-tools-preview", "rustc-dev", "rust-src"] diff --git a/src/tools/clippy/src/main.rs b/src/tools/clippy/src/main.rs index ea06743394d10..d13a831f5ff7d 100644 --- a/src/tools/clippy/src/main.rs +++ b/src/tools/clippy/src/main.rs @@ -59,7 +59,6 @@ pub fn main() { } struct ClippyCmd { - unstable_options: bool, cargo_subcommand: &'static str, args: Vec, clippy_args: Vec, @@ -105,21 +104,12 @@ impl ClippyCmd { } ClippyCmd { - unstable_options, cargo_subcommand, args, clippy_args, } } - fn path_env(&self) -> &'static str { - if self.unstable_options { - "RUSTC_WORKSPACE_WRAPPER" - } else { - "RUSTC_WRAPPER" - } - } - fn path() -> PathBuf { let mut path = env::current_exe() .expect("current executable path invalid") @@ -156,7 +146,7 @@ impl ClippyCmd { .map(|arg| format!("{}__CLIPPY_HACKERY__", arg)) .collect(); - cmd.env(self.path_env(), Self::path()) + cmd.env("RUSTC_WORKSPACE_WRAPPER", Self::path()) .envs(ClippyCmd::target_dir()) .env("CLIPPY_ARGS", clippy_args) .arg(self.cargo_subcommand) @@ -195,7 +185,7 @@ mod tests { #[should_panic] fn fix_without_unstable() { let args = "cargo clippy --fix".split_whitespace().map(ToString::to_string); - let _ = ClippyCmd::new(args); + ClippyCmd::new(args); } #[test] @@ -205,7 +195,6 @@ mod tests { .map(ToString::to_string); let cmd = ClippyCmd::new(args); assert_eq!("fix", cmd.cargo_subcommand); - assert_eq!("RUSTC_WORKSPACE_WRAPPER", cmd.path_env()); assert!(cmd.args.iter().any(|arg| arg.ends_with("unstable-options"))); } @@ -232,16 +221,5 @@ mod tests { let args = "cargo clippy".split_whitespace().map(ToString::to_string); let cmd = ClippyCmd::new(args); assert_eq!("check", cmd.cargo_subcommand); - assert_eq!("RUSTC_WRAPPER", cmd.path_env()); - } - - #[test] - fn check_unstable() { - let args = "cargo clippy -Zunstable-options" - .split_whitespace() - .map(ToString::to_string); - let cmd = ClippyCmd::new(args); - assert_eq!("check", cmd.cargo_subcommand); - assert_eq!("RUSTC_WORKSPACE_WRAPPER", cmd.path_env()); } } diff --git a/src/tools/clippy/tests/compile-test.rs b/src/tools/clippy/tests/compile-test.rs index 94f5e616cace8..c0b40add1096d 100644 --- a/src/tools/clippy/tests/compile-test.rs +++ b/src/tools/clippy/tests/compile-test.rs @@ -214,6 +214,7 @@ fn run_ui_cargo(config: &mut compiletest::Config) { Some("main.rs") => {}, _ => continue, } + set_var("CLIPPY_CONF_DIR", case.path()); let paths = compiletest::common::TestPaths { file: file_path, base: config.src_base.clone(), @@ -241,9 +242,11 @@ fn run_ui_cargo(config: &mut compiletest::Config) { let tests = compiletest::make_tests(&config); let current_dir = env::current_dir().unwrap(); + let conf_dir = var("CLIPPY_CONF_DIR").unwrap_or_default(); let filter = env::var("TESTNAME").ok(); let res = run_tests(&config, &filter, tests); env::set_current_dir(current_dir).unwrap(); + set_var("CLIPPY_CONF_DIR", conf_dir); match res { Ok(true) => {}, diff --git a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail/clippy.toml b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail/clippy.toml new file mode 100644 index 0000000000000..de4f04b24fc89 --- /dev/null +++ b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail/clippy.toml @@ -0,0 +1 @@ +cargo-ignore-publish = true diff --git a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish/Cargo.toml b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish/Cargo.toml new file mode 100644 index 0000000000000..7595696353cd4 --- /dev/null +++ b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "cargo_common_metadata" +version = "0.1.0" +publish = ["some-registry-name"] + +[workspace] diff --git a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish/src/main.rs b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish/src/main.rs new file mode 100644 index 0000000000000..27841e18aa9ef --- /dev/null +++ b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish/src/main.rs @@ -0,0 +1,4 @@ +// compile-flags: --crate-name=cargo_common_metadata +#![warn(clippy::cargo_common_metadata)] + +fn main() {} diff --git a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish/src/main.stderr b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish/src/main.stderr new file mode 100644 index 0000000000000..c8ae6c820df9d --- /dev/null +++ b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish/src/main.stderr @@ -0,0 +1,18 @@ +error: package `cargo_common_metadata` is missing `package.authors` metadata + | + = note: `-D clippy::cargo-common-metadata` implied by `-D warnings` + +error: package `cargo_common_metadata` is missing `package.description` metadata + +error: package `cargo_common_metadata` is missing `either package.license or package.license_file` metadata + +error: package `cargo_common_metadata` is missing `package.repository` metadata + +error: package `cargo_common_metadata` is missing `package.readme` metadata + +error: package `cargo_common_metadata` is missing `package.keywords` metadata + +error: package `cargo_common_metadata` is missing `package.categories` metadata + +error: aborting due to 7 previous errors + diff --git a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish_true/Cargo.toml b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish_true/Cargo.toml new file mode 100644 index 0000000000000..7e5b88383ccc3 --- /dev/null +++ b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish_true/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "cargo_common_metadata" +version = "0.1.0" +publish = true + +[workspace] diff --git a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish_true/src/main.rs b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish_true/src/main.rs new file mode 100644 index 0000000000000..27841e18aa9ef --- /dev/null +++ b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish_true/src/main.rs @@ -0,0 +1,4 @@ +// compile-flags: --crate-name=cargo_common_metadata +#![warn(clippy::cargo_common_metadata)] + +fn main() {} diff --git a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish_true/src/main.stderr b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish_true/src/main.stderr new file mode 100644 index 0000000000000..c8ae6c820df9d --- /dev/null +++ b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish_true/src/main.stderr @@ -0,0 +1,18 @@ +error: package `cargo_common_metadata` is missing `package.authors` metadata + | + = note: `-D clippy::cargo-common-metadata` implied by `-D warnings` + +error: package `cargo_common_metadata` is missing `package.description` metadata + +error: package `cargo_common_metadata` is missing `either package.license or package.license_file` metadata + +error: package `cargo_common_metadata` is missing `package.repository` metadata + +error: package `cargo_common_metadata` is missing `package.readme` metadata + +error: package `cargo_common_metadata` is missing `package.keywords` metadata + +error: package `cargo_common_metadata` is missing `package.categories` metadata + +error: aborting due to 7 previous errors + diff --git a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass/clippy.toml b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass/clippy.toml new file mode 100644 index 0000000000000..de4f04b24fc89 --- /dev/null +++ b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass/clippy.toml @@ -0,0 +1 @@ +cargo-ignore-publish = true diff --git a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass_publish_empty/Cargo.toml b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass_publish_empty/Cargo.toml new file mode 100644 index 0000000000000..0a879c99b5bd8 --- /dev/null +++ b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass_publish_empty/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "cargo_common_metadata" +version = "0.1.0" +publish = [] + +[workspace] diff --git a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass_publish_empty/src/main.rs b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass_publish_empty/src/main.rs new file mode 100644 index 0000000000000..27841e18aa9ef --- /dev/null +++ b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass_publish_empty/src/main.rs @@ -0,0 +1,4 @@ +// compile-flags: --crate-name=cargo_common_metadata +#![warn(clippy::cargo_common_metadata)] + +fn main() {} diff --git a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass_publish_false/Cargo.toml b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass_publish_false/Cargo.toml new file mode 100644 index 0000000000000..ae0a603299629 --- /dev/null +++ b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass_publish_false/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "cargo_common_metadata" +version = "0.1.0" +publish = false + +[workspace] diff --git a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass_publish_false/src/main.rs b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass_publish_false/src/main.rs new file mode 100644 index 0000000000000..27841e18aa9ef --- /dev/null +++ b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass_publish_false/src/main.rs @@ -0,0 +1,4 @@ +// compile-flags: --crate-name=cargo_common_metadata +#![warn(clippy::cargo_common_metadata)] + +fn main() {} diff --git a/src/tools/clippy/tests/ui-toml/toml_disallowed_method/clippy.toml b/src/tools/clippy/tests/ui-toml/toml_disallowed_method/clippy.toml index a1f515e443dc5..c0df3b6e8af5d 100644 --- a/src/tools/clippy/tests/ui-toml/toml_disallowed_method/clippy.toml +++ b/src/tools/clippy/tests/ui-toml/toml_disallowed_method/clippy.toml @@ -1 +1 @@ -disallowed-methods = ["core::iter::traits::iterator::Iterator::sum", "regex::re_unicode::Regex::is_match"] +disallowed-methods = ["core::iter::traits::iterator::Iterator::sum", "regex::re_unicode::Regex::is_match", "regex::re_unicode::Regex::new"] diff --git a/src/tools/clippy/tests/ui-toml/toml_disallowed_method/conf_disallowed_method.rs b/src/tools/clippy/tests/ui-toml/toml_disallowed_method/conf_disallowed_method.rs index 3d3f0729abd85..1901a99377ec6 100644 --- a/src/tools/clippy/tests/ui-toml/toml_disallowed_method/conf_disallowed_method.rs +++ b/src/tools/clippy/tests/ui-toml/toml_disallowed_method/conf_disallowed_method.rs @@ -4,10 +4,9 @@ extern crate regex; use regex::Regex; fn main() { - let a = vec![1, 2, 3, 4]; let re = Regex::new(r"ab.*c").unwrap(); - re.is_match("abc"); + let a = vec![1, 2, 3, 4]; a.iter().sum::(); } diff --git a/src/tools/clippy/tests/ui-toml/toml_disallowed_method/conf_disallowed_method.stderr b/src/tools/clippy/tests/ui-toml/toml_disallowed_method/conf_disallowed_method.stderr index ed91b5a6796d8..2b628c67fa751 100644 --- a/src/tools/clippy/tests/ui-toml/toml_disallowed_method/conf_disallowed_method.stderr +++ b/src/tools/clippy/tests/ui-toml/toml_disallowed_method/conf_disallowed_method.stderr @@ -1,16 +1,22 @@ +error: use of a disallowed method `regex::re_unicode::Regex::new` + --> $DIR/conf_disallowed_method.rs:7:14 + | +LL | let re = Regex::new(r"ab.*c").unwrap(); + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::disallowed-method` implied by `-D warnings` + error: use of a disallowed method `regex::re_unicode::Regex::is_match` - --> $DIR/conf_disallowed_method.rs:10:5 + --> $DIR/conf_disallowed_method.rs:8:5 | LL | re.is_match("abc"); | ^^^^^^^^^^^^^^^^^^ - | - = note: `-D clippy::disallowed-method` implied by `-D warnings` error: use of a disallowed method `core::iter::traits::iterator::Iterator::sum` - --> $DIR/conf_disallowed_method.rs:12:5 + --> $DIR/conf_disallowed_method.rs:11:5 | LL | a.iter().sum::(); | ^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors diff --git a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr index 7b3c476461d50..7ccd0b54845d1 100644 --- a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr +++ b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr @@ -1,4 +1,4 @@ -error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of `msrv`, `blacklisted-names`, `cognitive-complexity-threshold`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `verbose-bit-mask-threshold`, `literal-representation-threshold`, `trivial-copy-size-limit`, `pass-by-value-size-limit`, `too-many-lines-threshold`, `array-size-threshold`, `vec-box-size-threshold`, `max-trait-bounds`, `max-struct-bools`, `max-fn-params-bools`, `warn-on-all-wildcard-imports`, `disallowed-methods`, `unreadable-literal-lint-fractions`, `third-party` at line 5 column 1 +error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of `msrv`, `blacklisted-names`, `cognitive-complexity-threshold`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `verbose-bit-mask-threshold`, `literal-representation-threshold`, `trivial-copy-size-limit`, `pass-by-value-size-limit`, `too-many-lines-threshold`, `array-size-threshold`, `vec-box-size-threshold`, `max-trait-bounds`, `max-struct-bools`, `max-fn-params-bools`, `warn-on-all-wildcard-imports`, `disallowed-methods`, `unreadable-literal-lint-fractions`, `cargo-ignore-publish`, `third-party` at line 5 column 1 error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui/bytes_nth.fixed b/src/tools/clippy/tests/ui/bytes_nth.fixed new file mode 100644 index 0000000000000..bf68a7bbbf1d4 --- /dev/null +++ b/src/tools/clippy/tests/ui/bytes_nth.fixed @@ -0,0 +1,11 @@ +// run-rustfix + +#![allow(clippy::unnecessary_operation)] +#![warn(clippy::bytes_nth)] + +fn main() { + let s = String::from("String"); + s.as_bytes().get(3); + &s.as_bytes().get(3); + s[..].as_bytes().get(3); +} diff --git a/src/tools/clippy/tests/ui/bytes_nth.rs b/src/tools/clippy/tests/ui/bytes_nth.rs new file mode 100644 index 0000000000000..629812cc02cb8 --- /dev/null +++ b/src/tools/clippy/tests/ui/bytes_nth.rs @@ -0,0 +1,11 @@ +// run-rustfix + +#![allow(clippy::unnecessary_operation)] +#![warn(clippy::bytes_nth)] + +fn main() { + let s = String::from("String"); + s.bytes().nth(3); + &s.bytes().nth(3); + s[..].bytes().nth(3); +} diff --git a/src/tools/clippy/tests/ui/bytes_nth.stderr b/src/tools/clippy/tests/ui/bytes_nth.stderr new file mode 100644 index 0000000000000..9a5742928cd61 --- /dev/null +++ b/src/tools/clippy/tests/ui/bytes_nth.stderr @@ -0,0 +1,22 @@ +error: called `.byte().nth()` on a `String` + --> $DIR/bytes_nth.rs:8:5 + | +LL | s.bytes().nth(3); + | ^^^^^^^^^^^^^^^^ help: try: `s.as_bytes().get(3)` + | + = note: `-D clippy::bytes-nth` implied by `-D warnings` + +error: called `.byte().nth()` on a `String` + --> $DIR/bytes_nth.rs:9:6 + | +LL | &s.bytes().nth(3); + | ^^^^^^^^^^^^^^^^ help: try: `s.as_bytes().get(3)` + +error: called `.byte().nth()` on a `str` + --> $DIR/bytes_nth.rs:10:5 + | +LL | s[..].bytes().nth(3); + | ^^^^^^^^^^^^^^^^^^^^ help: try: `s[..].as_bytes().get(3)` + +error: aborting due to 3 previous errors + diff --git a/src/tools/clippy/tests/ui/collapsible_match.rs b/src/tools/clippy/tests/ui/collapsible_match.rs index a83e6c77b12e5..3294da7e8146f 100644 --- a/src/tools/clippy/tests/ui/collapsible_match.rs +++ b/src/tools/clippy/tests/ui/collapsible_match.rs @@ -224,6 +224,14 @@ fn negative_cases(res_opt: Result, String>, res_res: Result return, } + if let Ok(val) = res_opt { + if let Some(n) = val { + let _ = || { + // usage in closure + println!("{:?}", val); + }; + } + } } fn make() -> T { diff --git a/src/tools/clippy/tests/ui/filter_map_identity.fixed b/src/tools/clippy/tests/ui/filter_map_identity.fixed new file mode 100644 index 0000000000000..23ce28d8e9be4 --- /dev/null +++ b/src/tools/clippy/tests/ui/filter_map_identity.fixed @@ -0,0 +1,16 @@ +// run-rustfix + +#![allow(unused_imports)] +#![warn(clippy::filter_map_identity)] + +fn main() { + let iterator = vec![Some(1), None, Some(2)].into_iter(); + let _ = iterator.flatten(); + + let iterator = vec![Some(1), None, Some(2)].into_iter(); + let _ = iterator.flatten(); + + use std::convert::identity; + let iterator = vec![Some(1), None, Some(2)].into_iter(); + let _ = iterator.flatten(); +} diff --git a/src/tools/clippy/tests/ui/filter_map_identity.rs b/src/tools/clippy/tests/ui/filter_map_identity.rs new file mode 100644 index 0000000000000..e698df13eea47 --- /dev/null +++ b/src/tools/clippy/tests/ui/filter_map_identity.rs @@ -0,0 +1,16 @@ +// run-rustfix + +#![allow(unused_imports)] +#![warn(clippy::filter_map_identity)] + +fn main() { + let iterator = vec![Some(1), None, Some(2)].into_iter(); + let _ = iterator.filter_map(|x| x); + + let iterator = vec![Some(1), None, Some(2)].into_iter(); + let _ = iterator.filter_map(std::convert::identity); + + use std::convert::identity; + let iterator = vec![Some(1), None, Some(2)].into_iter(); + let _ = iterator.filter_map(identity); +} diff --git a/src/tools/clippy/tests/ui/filter_map_identity.stderr b/src/tools/clippy/tests/ui/filter_map_identity.stderr new file mode 100644 index 0000000000000..596a6320608c7 --- /dev/null +++ b/src/tools/clippy/tests/ui/filter_map_identity.stderr @@ -0,0 +1,22 @@ +error: called `filter_map(|x| x)` on an `Iterator` + --> $DIR/filter_map_identity.rs:8:22 + | +LL | let _ = iterator.filter_map(|x| x); + | ^^^^^^^^^^^^^^^^^ help: try: `flatten()` + | + = note: `-D clippy::filter-map-identity` implied by `-D warnings` + +error: called `filter_map(std::convert::identity)` on an `Iterator` + --> $DIR/filter_map_identity.rs:11:22 + | +LL | let _ = iterator.filter_map(std::convert::identity); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `flatten()` + +error: called `filter_map(std::convert::identity)` on an `Iterator` + --> $DIR/filter_map_identity.rs:15:22 + | +LL | let _ = iterator.filter_map(identity); + | ^^^^^^^^^^^^^^^^^^^^ help: try: `flatten()` + +error: aborting due to 3 previous errors + diff --git a/src/tools/clippy/tests/ui/unnecessary_flat_map.fixed b/src/tools/clippy/tests/ui/flat_map_identity.fixed similarity index 100% rename from src/tools/clippy/tests/ui/unnecessary_flat_map.fixed rename to src/tools/clippy/tests/ui/flat_map_identity.fixed diff --git a/src/tools/clippy/tests/ui/unnecessary_flat_map.rs b/src/tools/clippy/tests/ui/flat_map_identity.rs similarity index 100% rename from src/tools/clippy/tests/ui/unnecessary_flat_map.rs rename to src/tools/clippy/tests/ui/flat_map_identity.rs diff --git a/src/tools/clippy/tests/ui/unnecessary_flat_map.stderr b/src/tools/clippy/tests/ui/flat_map_identity.stderr similarity index 85% rename from src/tools/clippy/tests/ui/unnecessary_flat_map.stderr rename to src/tools/clippy/tests/ui/flat_map_identity.stderr index a1cd5745e4949..e4686ae5a5493 100644 --- a/src/tools/clippy/tests/ui/unnecessary_flat_map.stderr +++ b/src/tools/clippy/tests/ui/flat_map_identity.stderr @@ -1,5 +1,5 @@ error: called `flat_map(|x| x)` on an `Iterator` - --> $DIR/unnecessary_flat_map.rs:10:22 + --> $DIR/flat_map_identity.rs:10:22 | LL | let _ = iterator.flat_map(|x| x); | ^^^^^^^^^^^^^^^ help: try: `flatten()` @@ -7,7 +7,7 @@ LL | let _ = iterator.flat_map(|x| x); = note: `-D clippy::flat-map-identity` implied by `-D warnings` error: called `flat_map(std::convert::identity)` on an `Iterator` - --> $DIR/unnecessary_flat_map.rs:13:22 + --> $DIR/flat_map_identity.rs:13:22 | LL | let _ = iterator.flat_map(convert::identity); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `flatten()` diff --git a/src/tools/clippy/tests/ui/from_iter_instead_of_collect.fixed b/src/tools/clippy/tests/ui/from_iter_instead_of_collect.fixed new file mode 100644 index 0000000000000..b5f548810e65a --- /dev/null +++ b/src/tools/clippy/tests/ui/from_iter_instead_of_collect.fixed @@ -0,0 +1,48 @@ +// run-rustfix + +#![warn(clippy::from_iter_instead_of_collect)] +#![allow(unused_imports)] + +use std::collections::{BTreeMap, BTreeSet, HashMap, VecDeque}; +use std::iter::FromIterator; + +fn main() { + let iter_expr = std::iter::repeat(5).take(5); + let _ = iter_expr.collect::>(); + + let _ = vec![5, 5, 5, 5].iter().enumerate().collect::>(); + + Vec::from_iter(vec![42u32]); + + let a = vec![0, 1, 2]; + assert_eq!(a, (0..3).collect::>()); + assert_eq!(a, (0..3).collect::>()); + + let mut b = (0..3).collect::>(); + b.push_back(4); + + let mut b = (0..3).collect::>(); + b.push_back(4); + + { + use std::collections; + let mut b = (0..3).collect::>(); + b.push_back(4); + } + + let values = [(0, 'a'), (1, 'b'), (2, 'c'), (3, 'd')]; + let bm = values.iter().cloned().collect::>(); + let mut bar = bm.range(0..2).collect::>(); + bar.insert(&4, &'e'); + + let mut bts = (0..3).collect::>(); + bts.insert(2); + { + use std::collections; + let _ = (0..3).collect::>(); + let _ = (0..3).collect::>(); + } + + for _i in [1, 2, 3].iter().collect::>() {} + for _i in [1, 2, 3].iter().collect::>() {} +} diff --git a/src/tools/clippy/tests/ui/from_iter_instead_of_collect.rs b/src/tools/clippy/tests/ui/from_iter_instead_of_collect.rs index 045eb3133d3c4..b842b5451d1c8 100644 --- a/src/tools/clippy/tests/ui/from_iter_instead_of_collect.rs +++ b/src/tools/clippy/tests/ui/from_iter_instead_of_collect.rs @@ -1,13 +1,48 @@ +// run-rustfix + #![warn(clippy::from_iter_instead_of_collect)] +#![allow(unused_imports)] -use std::collections::HashMap; +use std::collections::{BTreeMap, BTreeSet, HashMap, VecDeque}; use std::iter::FromIterator; fn main() { let iter_expr = std::iter::repeat(5).take(5); - Vec::from_iter(iter_expr); + let _ = Vec::from_iter(iter_expr); - HashMap::::from_iter(vec![5, 5, 5, 5].iter().enumerate()); + let _ = HashMap::::from_iter(vec![5, 5, 5, 5].iter().enumerate()); Vec::from_iter(vec![42u32]); + + let a = vec![0, 1, 2]; + assert_eq!(a, Vec::from_iter(0..3)); + assert_eq!(a, Vec::::from_iter(0..3)); + + let mut b = VecDeque::from_iter(0..3); + b.push_back(4); + + let mut b = VecDeque::::from_iter(0..3); + b.push_back(4); + + { + use std::collections; + let mut b = collections::VecDeque::::from_iter(0..3); + b.push_back(4); + } + + let values = [(0, 'a'), (1, 'b'), (2, 'c'), (3, 'd')]; + let bm = BTreeMap::from_iter(values.iter().cloned()); + let mut bar = BTreeMap::from_iter(bm.range(0..2)); + bar.insert(&4, &'e'); + + let mut bts = BTreeSet::from_iter(0..3); + bts.insert(2); + { + use std::collections; + let _ = collections::BTreeSet::from_iter(0..3); + let _ = collections::BTreeSet::::from_iter(0..3); + } + + for _i in Vec::from_iter([1, 2, 3].iter()) {} + for _i in Vec::<&i32>::from_iter([1, 2, 3].iter()) {} } diff --git a/src/tools/clippy/tests/ui/from_iter_instead_of_collect.stderr b/src/tools/clippy/tests/ui/from_iter_instead_of_collect.stderr index 46bdc2f4e199b..434734c9a213d 100644 --- a/src/tools/clippy/tests/ui/from_iter_instead_of_collect.stderr +++ b/src/tools/clippy/tests/ui/from_iter_instead_of_collect.stderr @@ -1,16 +1,88 @@ error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:8:5 + --> $DIR/from_iter_instead_of_collect.rs:11:13 | -LL | Vec::from_iter(iter_expr); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `iter_expr.collect()` +LL | let _ = Vec::from_iter(iter_expr); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `iter_expr.collect::>()` | = note: `-D clippy::from-iter-instead-of-collect` implied by `-D warnings` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:10:5 + --> $DIR/from_iter_instead_of_collect.rs:13:13 | -LL | HashMap::::from_iter(vec![5, 5, 5, 5].iter().enumerate()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `vec![5, 5, 5, 5].iter().enumerate().collect()` +LL | let _ = HashMap::::from_iter(vec![5, 5, 5, 5].iter().enumerate()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `vec![5, 5, 5, 5].iter().enumerate().collect::>()` -error: aborting due to 2 previous errors +error: usage of `FromIterator::from_iter` + --> $DIR/from_iter_instead_of_collect.rs:18:19 + | +LL | assert_eq!(a, Vec::from_iter(0..3)); + | ^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` + +error: usage of `FromIterator::from_iter` + --> $DIR/from_iter_instead_of_collect.rs:19:19 + | +LL | assert_eq!(a, Vec::::from_iter(0..3)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` + +error: usage of `FromIterator::from_iter` + --> $DIR/from_iter_instead_of_collect.rs:21:17 + | +LL | let mut b = VecDeque::from_iter(0..3); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` + +error: usage of `FromIterator::from_iter` + --> $DIR/from_iter_instead_of_collect.rs:24:17 + | +LL | let mut b = VecDeque::::from_iter(0..3); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` + +error: usage of `FromIterator::from_iter` + --> $DIR/from_iter_instead_of_collect.rs:29:21 + | +LL | let mut b = collections::VecDeque::::from_iter(0..3); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` + +error: usage of `FromIterator::from_iter` + --> $DIR/from_iter_instead_of_collect.rs:34:14 + | +LL | let bm = BTreeMap::from_iter(values.iter().cloned()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `values.iter().cloned().collect::>()` + +error: usage of `FromIterator::from_iter` + --> $DIR/from_iter_instead_of_collect.rs:35:19 + | +LL | let mut bar = BTreeMap::from_iter(bm.range(0..2)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `bm.range(0..2).collect::>()` + +error: usage of `FromIterator::from_iter` + --> $DIR/from_iter_instead_of_collect.rs:38:19 + | +LL | let mut bts = BTreeSet::from_iter(0..3); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` + +error: usage of `FromIterator::from_iter` + --> $DIR/from_iter_instead_of_collect.rs:42:17 + | +LL | let _ = collections::BTreeSet::from_iter(0..3); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` + +error: usage of `FromIterator::from_iter` + --> $DIR/from_iter_instead_of_collect.rs:43:17 + | +LL | let _ = collections::BTreeSet::::from_iter(0..3); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` + +error: usage of `FromIterator::from_iter` + --> $DIR/from_iter_instead_of_collect.rs:46:15 + | +LL | for _i in Vec::from_iter([1, 2, 3].iter()) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `[1, 2, 3].iter().collect::>()` + +error: usage of `FromIterator::from_iter` + --> $DIR/from_iter_instead_of_collect.rs:47:15 + | +LL | for _i in Vec::<&i32>::from_iter([1, 2, 3].iter()) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `[1, 2, 3].iter().collect::>()` + +error: aborting due to 14 previous errors diff --git a/src/tools/clippy/tests/ui/let_underscore_drop.rs b/src/tools/clippy/tests/ui/let_underscore_drop.rs index 98593edb9c591..50744f81c3cf8 100644 --- a/src/tools/clippy/tests/ui/let_underscore_drop.rs +++ b/src/tools/clippy/tests/ui/let_underscore_drop.rs @@ -16,4 +16,12 @@ fn main() { let _ = Box::new(()); let _ = Droppable; let _ = Some(Droppable); + + // no lint for reference + let _ = droppable_ref(); +} + +#[must_use] +fn droppable_ref() -> &'static mut Droppable { + unimplemented!() } diff --git a/src/tools/clippy/tests/ui/manual_flatten.rs b/src/tools/clippy/tests/ui/manual_flatten.rs new file mode 100644 index 0000000000000..cff68eca93374 --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_flatten.rs @@ -0,0 +1,76 @@ +#![warn(clippy::manual_flatten)] + +fn main() { + // Test for loop over implicitly adjusted `Iterator` with `if let` expression + let x = vec![Some(1), Some(2), Some(3)]; + for n in x { + if let Some(y) = n { + println!("{}", y); + } + } + + // Test for loop over implicitly implicitly adjusted `Iterator` with `if let` statement + let y: Vec> = vec![]; + for n in y.clone() { + if let Ok(n) = n { + println!("{}", n); + }; + } + + // Test for loop over by reference + for n in &y { + if let Ok(n) = n { + println!("{}", n); + } + } + + // Test for loop over an implicit reference + // Note: if `clippy::manual_flatten` is made autofixable, this case will + // lead to a follow-up lint `clippy::into_iter_on_ref` + let z = &y; + for n in z { + if let Ok(n) = n { + println!("{}", n); + } + } + + // Test for loop over `Iterator` with `if let` expression + let z = vec![Some(1), Some(2), Some(3)]; + let z = z.iter(); + for n in z { + if let Some(m) = n { + println!("{}", m); + } + } + + // Using the `None` variant should not trigger the lint + // Note: for an autofixable suggestion, the binding in the for loop has to take the + // name of the binding in the `if let` + let z = vec![Some(1), Some(2), Some(3)]; + for n in z { + if n.is_none() { + println!("Nada."); + } + } + + // Using the `Err` variant should not trigger the lint + for n in y.clone() { + if let Err(e) = n { + println!("Oops: {}!", e); + } + } + + // Having an else clause should not trigger the lint + for n in y.clone() { + if let Ok(n) = n { + println!("{}", n); + } else { + println!("Oops!"); + } + } + + // Using manual flatten should not trigger the lint + for n in vec![Some(1), Some(2), Some(3)].iter().flatten() { + println!("{}", n); + } +} diff --git a/src/tools/clippy/tests/ui/manual_flatten.stderr b/src/tools/clippy/tests/ui/manual_flatten.stderr new file mode 100644 index 0000000000000..855dd9130e2fb --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_flatten.stderr @@ -0,0 +1,108 @@ +error: unnecessary `if let` since only the `Some` variant of the iterator element is used + --> $DIR/manual_flatten.rs:6:5 + | +LL | for n in x { + | ^ - help: try: `x.into_iter().flatten()` + | _____| + | | +LL | | if let Some(y) = n { +LL | | println!("{}", y); +LL | | } +LL | | } + | |_____^ + | + = note: `-D clippy::manual-flatten` implied by `-D warnings` +help: ...and remove the `if let` statement in the for loop + --> $DIR/manual_flatten.rs:7:9 + | +LL | / if let Some(y) = n { +LL | | println!("{}", y); +LL | | } + | |_________^ + +error: unnecessary `if let` since only the `Ok` variant of the iterator element is used + --> $DIR/manual_flatten.rs:14:5 + | +LL | for n in y.clone() { + | ^ --------- help: try: `y.clone().into_iter().flatten()` + | _____| + | | +LL | | if let Ok(n) = n { +LL | | println!("{}", n); +LL | | }; +LL | | } + | |_____^ + | +help: ...and remove the `if let` statement in the for loop + --> $DIR/manual_flatten.rs:15:9 + | +LL | / if let Ok(n) = n { +LL | | println!("{}", n); +LL | | }; + | |_________^ + +error: unnecessary `if let` since only the `Ok` variant of the iterator element is used + --> $DIR/manual_flatten.rs:21:5 + | +LL | for n in &y { + | ^ -- help: try: `y.iter().flatten()` + | _____| + | | +LL | | if let Ok(n) = n { +LL | | println!("{}", n); +LL | | } +LL | | } + | |_____^ + | +help: ...and remove the `if let` statement in the for loop + --> $DIR/manual_flatten.rs:22:9 + | +LL | / if let Ok(n) = n { +LL | | println!("{}", n); +LL | | } + | |_________^ + +error: unnecessary `if let` since only the `Ok` variant of the iterator element is used + --> $DIR/manual_flatten.rs:31:5 + | +LL | for n in z { + | ^ - help: try: `z.into_iter().flatten()` + | _____| + | | +LL | | if let Ok(n) = n { +LL | | println!("{}", n); +LL | | } +LL | | } + | |_____^ + | +help: ...and remove the `if let` statement in the for loop + --> $DIR/manual_flatten.rs:32:9 + | +LL | / if let Ok(n) = n { +LL | | println!("{}", n); +LL | | } + | |_________^ + +error: unnecessary `if let` since only the `Some` variant of the iterator element is used + --> $DIR/manual_flatten.rs:40:5 + | +LL | for n in z { + | ^ - help: try: `z.flatten()` + | _____| + | | +LL | | if let Some(m) = n { +LL | | println!("{}", m); +LL | | } +LL | | } + | |_____^ + | +help: ...and remove the `if let` statement in the for loop + --> $DIR/manual_flatten.rs:41:9 + | +LL | / if let Some(m) = n { +LL | | println!("{}", m); +LL | | } + | |_________^ + +error: aborting due to 5 previous errors + diff --git a/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.rs b/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.rs new file mode 100644 index 0000000000000..0abe2cca26757 --- /dev/null +++ b/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.rs @@ -0,0 +1,55 @@ +#![warn(clippy::semicolon_if_nothing_returned)] +#![feature(label_break_value)] + +fn get_unit() {} + +// the functions below trigger the lint +fn main() { + println!("Hello") +} + +fn hello() { + get_unit() +} + +fn basic101(x: i32) { + let y: i32; + y = x + 1 +} + +// this is fine +fn print_sum(a: i32, b: i32) { + println!("{}", a + b); + assert_eq!(true, false); +} + +fn foo(x: i32) { + let y: i32; + if x < 1 { + y = 4; + } else { + y = 5; + } +} + +fn bar(x: i32) { + let y: i32; + match x { + 1 => y = 4, + _ => y = 32, + } +} + +fn foobar(x: i32) { + let y: i32; + 'label: { + y = x + 1; + } +} + +fn loop_test(x: i32) { + let y: i32; + for &ext in &["stdout", "stderr", "fixed"] { + println!("{}", ext); + } +} diff --git a/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.stderr b/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.stderr new file mode 100644 index 0000000000000..b73f89675383f --- /dev/null +++ b/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.stderr @@ -0,0 +1,22 @@ +error: consider adding a `;` to the last statement for consistent formatting + --> $DIR/semicolon_if_nothing_returned.rs:8:5 + | +LL | println!("Hello") + | ^^^^^^^^^^^^^^^^^ help: add a `;` here: `println!("Hello");` + | + = note: `-D clippy::semicolon-if-nothing-returned` implied by `-D warnings` + +error: consider adding a `;` to the last statement for consistent formatting + --> $DIR/semicolon_if_nothing_returned.rs:12:5 + | +LL | get_unit() + | ^^^^^^^^^^ help: add a `;` here: `get_unit();` + +error: consider adding a `;` to the last statement for consistent formatting + --> $DIR/semicolon_if_nothing_returned.rs:17:5 + | +LL | y = x + 1 + | ^^^^^^^^^ help: add a `;` here: `y = x + 1;` + +error: aborting due to 3 previous errors + diff --git a/src/tools/clippy/tests/ui/zero_div_zero.rs b/src/tools/clippy/tests/ui/zero_div_zero.rs index 09db130a76431..ed3a9208fc3f0 100644 --- a/src/tools/clippy/tests/ui/zero_div_zero.rs +++ b/src/tools/clippy/tests/ui/zero_div_zero.rs @@ -7,7 +7,7 @@ fn main() { let one_more_f64_nan = 0.0f64 / 0.0f64; let zero = 0.0; let other_zero = 0.0; - let other_nan = zero / other_zero; // fine - this lint doesn't propegate constants. + let other_nan = zero / other_zero; // fine - this lint doesn't propagate constants. let not_nan = 2.0 / 0.0; // not an error: 2/0 = inf let also_not_nan = 0.0 / 2.0; // not an error: 0/2 = 0 } diff --git a/src/tools/clippy/tests/versioncheck.rs b/src/tools/clippy/tests/versioncheck.rs index 76b6126c76c6a..bc5ed0816cc81 100644 --- a/src/tools/clippy/tests/versioncheck.rs +++ b/src/tools/clippy/tests/versioncheck.rs @@ -23,6 +23,12 @@ fn check_that_clippy_lints_has_the_same_version_as_clippy() { #[test] fn check_that_clippy_has_the_same_major_version_as_rustc() { + // do not run this test inside the upstream rustc repo: + // https://github.com/rust-lang/rust-clippy/issues/6683 + if option_env!("RUSTC_TEST_SUITE").is_some() { + return; + } + let clippy_version = rustc_tools_util::get_version_info!(); let clippy_major = clippy_version.major; let clippy_minor = clippy_version.minor; diff --git a/src/tools/clippy/triagebot.toml b/src/tools/clippy/triagebot.toml index b9549be3a8b63..b0a13f827d6cd 100644 --- a/src/tools/clippy/triagebot.toml +++ b/src/tools/clippy/triagebot.toml @@ -1,6 +1,6 @@ [relabel] allow-unauthenticated = [ - "A-*", "C-*", "E-*", "L-*", "M-*", "O-*", "P-*", "S-*", "T-*", + "A-*", "C-*", "E-*", "I-*", "L-*", "P-*", "S-*", "T-*", "good-first-issue" ]