diff options
Diffstat (limited to 'src/tools')
157 files changed, 1742 insertions, 1433 deletions
diff --git a/src/tools/build_helper/Cargo.toml b/src/tools/build_helper/Cargo.toml deleted file mode 100644 index 66894e1abc4..00000000000 --- a/src/tools/build_helper/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "build_helper" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -serde = "1" -serde_derive = "1" diff --git a/src/tools/build_helper/README.md b/src/tools/build_helper/README.md deleted file mode 100644 index f81b631c3fd..00000000000 --- a/src/tools/build_helper/README.md +++ /dev/null @@ -1 +0,0 @@ -Types and functions shared across tools in this workspace. diff --git a/src/tools/build_helper/src/ci.rs b/src/tools/build_helper/src/ci.rs deleted file mode 100644 index 60f319129a0..00000000000 --- a/src/tools/build_helper/src/ci.rs +++ /dev/null @@ -1,95 +0,0 @@ -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub enum CiEnv { - /// Not a CI environment. - None, - /// The GitHub Actions environment, for Linux (including Docker), Windows and macOS builds. - GitHubActions, -} - -impl CiEnv { - /// Obtains the current CI environment. - pub fn current() -> CiEnv { - if std::env::var("GITHUB_ACTIONS").map_or(false, |e| e == "true") { - CiEnv::GitHubActions - } else { - CiEnv::None - } - } - - pub fn is_ci() -> bool { - Self::current() != CiEnv::None - } - - /// Checks if running in rust-lang/rust managed CI job. - pub fn is_rust_lang_managed_ci_job() -> bool { - Self::is_ci() - // If both are present, we can assume it's an upstream CI job - // as they are always set unconditionally. - && std::env::var_os("CI_JOB_NAME").is_some() - && std::env::var_os("TOOLSTATE_REPO").is_some() - } -} - -pub mod gha { - use std::sync::Mutex; - - static ACTIVE_GROUPS: Mutex<Vec<String>> = Mutex::new(Vec::new()); - - /// All github actions log messages from this call to the Drop of the return value - /// will be grouped and hidden by default in logs. Note that since github actions doesn't - /// support group nesting, any active group will be first finished when a subgroup is started, - /// and then re-started when the subgroup finishes. - #[track_caller] - pub fn group(name: impl std::fmt::Display) -> Group { - let mut groups = ACTIVE_GROUPS.lock().unwrap(); - - // A group is currently active. End it first to avoid nesting. - if !groups.is_empty() { - end_group(); - } - - let name = name.to_string(); - start_group(&name); - groups.push(name); - Group(()) - } - - /// A guard that closes the current github actions log group on drop. - #[must_use] - pub struct Group(()); - - impl Drop for Group { - fn drop(&mut self) { - end_group(); - - let mut groups = ACTIVE_GROUPS.lock().unwrap(); - // Remove the current group - groups.pop(); - - // If there was some previous group, restart it - if is_in_gha() { - if let Some(name) = groups.last() { - start_group(format!("{name} (continued)")); - } - } - } - } - - fn start_group(name: impl std::fmt::Display) { - if is_in_gha() { - println!("::group::{name}"); - } else { - println!("{name}") - } - } - - fn end_group() { - if is_in_gha() { - println!("::endgroup::"); - } - } - - fn is_in_gha() -> bool { - std::env::var_os("GITHUB_ACTIONS").is_some() - } -} diff --git a/src/tools/build_helper/src/drop_bomb/mod.rs b/src/tools/build_helper/src/drop_bomb/mod.rs deleted file mode 100644 index 0a5bb04b55b..00000000000 --- a/src/tools/build_helper/src/drop_bomb/mod.rs +++ /dev/null @@ -1,54 +0,0 @@ -//! This module implements "drop bombs" intended for use by command wrappers to ensure that the -//! constructed commands are *eventually* executed. This is exactly like `rustc_errors::Diag` where -//! we force every `Diag` to be consumed or we emit a bug, but we panic instead. -//! -//! This is adapted from <https://docs.rs/drop_bomb/latest/drop_bomb/> and simplified for our -//! purposes. - -use std::ffi::{OsStr, OsString}; -use std::panic; - -#[cfg(test)] -mod tests; - -#[derive(Debug)] -pub struct DropBomb { - command: OsString, - defused: bool, - armed_location: panic::Location<'static>, -} - -impl DropBomb { - /// Arm a [`DropBomb`]. If the value is dropped without being [`defused`][Self::defused], then - /// it will panic. It is expected that the command wrapper uses `#[track_caller]` to help - /// propagate the caller location. - #[track_caller] - pub fn arm<S: AsRef<OsStr>>(command: S) -> DropBomb { - DropBomb { - command: command.as_ref().into(), - defused: false, - armed_location: *panic::Location::caller(), - } - } - - pub fn get_created_location(&self) -> panic::Location<'static> { - self.armed_location - } - - /// Defuse the [`DropBomb`]. This will prevent the drop bomb from panicking when dropped. - pub fn defuse(&mut self) { - self.defused = true; - } -} - -impl Drop for DropBomb { - fn drop(&mut self) { - if !self.defused && !std::thread::panicking() { - panic!( - "command constructed at `{}` was dropped without being executed: `{}`", - self.armed_location, - self.command.to_string_lossy() - ) - } - } -} diff --git a/src/tools/build_helper/src/drop_bomb/tests.rs b/src/tools/build_helper/src/drop_bomb/tests.rs deleted file mode 100644 index 4a488c0f670..00000000000 --- a/src/tools/build_helper/src/drop_bomb/tests.rs +++ /dev/null @@ -1,15 +0,0 @@ -use super::DropBomb; - -#[test] -#[should_panic] -fn test_arm() { - let bomb = DropBomb::arm("hi :3"); - drop(bomb); // <- armed bomb should explode when not defused -} - -#[test] -fn test_defuse() { - let mut bomb = DropBomb::arm("hi :3"); - bomb.defuse(); - drop(bomb); // <- defused bomb should not explode -} diff --git a/src/tools/build_helper/src/git.rs b/src/tools/build_helper/src/git.rs deleted file mode 100644 index 2aad5650fa8..00000000000 --- a/src/tools/build_helper/src/git.rs +++ /dev/null @@ -1,208 +0,0 @@ -use std::path::{Path, PathBuf}; -use std::process::{Command, Stdio}; - -use crate::ci::CiEnv; - -pub struct GitConfig<'a> { - pub git_repository: &'a str, - pub nightly_branch: &'a str, - pub git_merge_commit_email: &'a str, -} - -/// Runs a command and returns the output -pub fn output_result(cmd: &mut Command) -> Result<String, String> { - let output = match cmd.stderr(Stdio::inherit()).output() { - Ok(status) => status, - Err(e) => return Err(format!("failed to run command: {:?}: {}", cmd, e)), - }; - if !output.status.success() { - return Err(format!( - "command did not execute successfully: {:?}\n\ - expected success, got: {}\n{}", - cmd, - output.status, - String::from_utf8(output.stderr).map_err(|err| format!("{err:?}"))? - )); - } - String::from_utf8(output.stdout).map_err(|err| format!("{err:?}")) -} - -/// Finds the remote for rust-lang/rust. -/// For example for these remotes it will return `upstream`. -/// ```text -/// origin https://github.com/Nilstrieb/rust.git (fetch) -/// origin https://github.com/Nilstrieb/rust.git (push) -/// upstream https://github.com/rust-lang/rust (fetch) -/// upstream https://github.com/rust-lang/rust (push) -/// ``` -pub fn get_rust_lang_rust_remote( - config: &GitConfig<'_>, - git_dir: Option<&Path>, -) -> Result<String, String> { - let mut git = Command::new("git"); - if let Some(git_dir) = git_dir { - git.current_dir(git_dir); - } - git.args(["config", "--local", "--get-regex", "remote\\..*\\.url"]); - let stdout = output_result(&mut git)?; - - let rust_lang_remote = stdout - .lines() - .find(|remote| remote.contains(config.git_repository)) - .ok_or_else(|| format!("{} remote not found", config.git_repository))?; - - let remote_name = - rust_lang_remote.split('.').nth(1).ok_or_else(|| "remote name not found".to_owned())?; - Ok(remote_name.into()) -} - -pub fn rev_exists(rev: &str, git_dir: Option<&Path>) -> Result<bool, String> { - let mut git = Command::new("git"); - if let Some(git_dir) = git_dir { - git.current_dir(git_dir); - } - git.args(["rev-parse", rev]); - let output = git.output().map_err(|err| format!("{err:?}"))?; - - match output.status.code() { - Some(0) => Ok(true), - Some(128) => Ok(false), - None => Err(format!( - "git didn't exit properly: {}", - String::from_utf8(output.stderr).map_err(|err| format!("{err:?}"))? - )), - Some(code) => Err(format!( - "git command exited with status code: {code}: {}", - String::from_utf8(output.stderr).map_err(|err| format!("{err:?}"))? - )), - } -} - -/// Returns the master branch from which we can take diffs to see changes. -/// This will usually be rust-lang/rust master, but sometimes this might not exist. -/// This could be because the user is updating their forked master branch using the GitHub UI -/// and therefore doesn't need an upstream master branch checked out. -/// We will then fall back to origin/master in the hope that at least this exists. -pub fn updated_master_branch( - config: &GitConfig<'_>, - git_dir: Option<&Path>, -) -> Result<String, String> { - let upstream_remote = get_rust_lang_rust_remote(config, git_dir)?; - let branch = config.nightly_branch; - for upstream_master in [format!("{upstream_remote}/{branch}"), format!("origin/{branch}")] { - if rev_exists(&upstream_master, git_dir)? { - return Ok(upstream_master); - } - } - - Err("Cannot find any suitable upstream master branch".to_owned()) -} - -/// Finds the nearest merge commit by comparing the local `HEAD` with the upstream branch's state. -/// To work correctly, the upstream remote must be properly configured using `git remote add <name> <url>`. -/// In most cases `get_closest_merge_commit` is the function you are looking for as it doesn't require remote -/// to be configured. -fn git_upstream_merge_base( - config: &GitConfig<'_>, - git_dir: Option<&Path>, -) -> Result<String, String> { - let updated_master = updated_master_branch(config, git_dir)?; - let mut git = Command::new("git"); - if let Some(git_dir) = git_dir { - git.current_dir(git_dir); - } - Ok(output_result(git.arg("merge-base").arg(&updated_master).arg("HEAD"))?.trim().to_owned()) -} - -/// Searches for the nearest merge commit in the repository that also exists upstream. -/// -/// It looks for the most recent commit made by the merge bot by matching the author's email -/// address with the merge bot's email. -pub fn get_closest_merge_commit( - git_dir: Option<&Path>, - config: &GitConfig<'_>, - target_paths: &[PathBuf], -) -> Result<String, String> { - let mut git = Command::new("git"); - - if let Some(git_dir) = git_dir { - git.current_dir(git_dir); - } - - let merge_base = { - if CiEnv::is_ci() { - git_upstream_merge_base(config, git_dir).unwrap() - } else { - // For non-CI environments, ignore rust-lang/rust upstream as it usually gets - // outdated very quickly. - "HEAD".to_string() - } - }; - - git.args([ - "rev-list", - &format!("--author={}", config.git_merge_commit_email), - "-n1", - "--first-parent", - &merge_base, - ]); - - if !target_paths.is_empty() { - git.arg("--").args(target_paths); - } - - Ok(output_result(&mut git)?.trim().to_owned()) -} - -/// Returns the files that have been modified in the current branch compared to the master branch. -/// The `extensions` parameter can be used to filter the files by their extension. -/// Does not include removed files. -/// If `extensions` is empty, all files will be returned. -pub fn get_git_modified_files( - config: &GitConfig<'_>, - git_dir: Option<&Path>, - extensions: &[&str], -) -> Result<Option<Vec<String>>, String> { - let merge_base = get_closest_merge_commit(git_dir, config, &[])?; - - let mut git = Command::new("git"); - if let Some(git_dir) = git_dir { - git.current_dir(git_dir); - } - let files = output_result(git.args(["diff-index", "--name-status", merge_base.trim()]))? - .lines() - .filter_map(|f| { - let (status, name) = f.trim().split_once(char::is_whitespace).unwrap(); - if status == "D" { - None - } else if Path::new(name).extension().map_or(false, |ext| { - extensions.is_empty() || extensions.contains(&ext.to_str().unwrap()) - }) { - Some(name.to_owned()) - } else { - None - } - }) - .collect(); - Ok(Some(files)) -} - -/// Returns the files that haven't been added to git yet. -pub fn get_git_untracked_files( - config: &GitConfig<'_>, - git_dir: Option<&Path>, -) -> Result<Option<Vec<String>>, String> { - let Ok(_updated_master) = updated_master_branch(config, git_dir) else { - return Ok(None); - }; - let mut git = Command::new("git"); - if let Some(git_dir) = git_dir { - git.current_dir(git_dir); - } - - let files = output_result(git.arg("ls-files").arg("--others").arg("--exclude-standard"))? - .lines() - .map(|s| s.trim().to_owned()) - .collect(); - Ok(Some(files)) -} diff --git a/src/tools/build_helper/src/lib.rs b/src/tools/build_helper/src/lib.rs deleted file mode 100644 index 4a4f0ca2a9d..00000000000 --- a/src/tools/build_helper/src/lib.rs +++ /dev/null @@ -1,31 +0,0 @@ -//! Types and functions shared across tools in this workspace. - -pub mod ci; -pub mod drop_bomb; -pub mod git; -pub mod metrics; -pub mod stage0_parser; -pub mod util; - -/// The default set of crates for opt-dist to collect LLVM profiles. -pub const LLVM_PGO_CRATES: &[&str] = &[ - "syn-1.0.89", - "cargo-0.60.0", - "serde-1.0.136", - "ripgrep-13.0.0", - "regex-1.5.5", - "clap-3.1.6", - "hyper-0.14.18", -]; - -/// The default set of crates for opt-dist to collect rustc profiles. -pub const RUSTC_PGO_CRATES: &[&str] = &[ - "externs", - "ctfe-stress-5", - "cargo-0.60.0", - "token-stream-stress", - "match-stress", - "tuple-stress", - "diesel-1.4.8", - "bitmaps-3.1.0", -]; diff --git a/src/tools/build_helper/src/metrics.rs b/src/tools/build_helper/src/metrics.rs deleted file mode 100644 index 2d0c66a8f33..00000000000 --- a/src/tools/build_helper/src/metrics.rs +++ /dev/null @@ -1,92 +0,0 @@ -use serde_derive::{Deserialize, Serialize}; - -#[derive(Serialize, Deserialize)] -#[serde(rename_all = "snake_case")] -pub struct JsonRoot { - #[serde(default)] // For version 0 the field was not present. - pub format_version: usize, - pub system_stats: JsonInvocationSystemStats, - pub invocations: Vec<JsonInvocation>, -} - -#[derive(Serialize, Deserialize)] -#[serde(rename_all = "snake_case")] -pub struct JsonInvocation { - // Unix timestamp in seconds - // - // This is necessary to easily correlate this invocation with logs or other data. - pub start_time: u64, - pub duration_including_children_sec: f64, - pub children: Vec<JsonNode>, -} - -#[derive(Serialize, Deserialize)] -#[serde(tag = "kind", rename_all = "snake_case")] -pub enum JsonNode { - RustbuildStep { - #[serde(rename = "type")] - type_: String, - debug_repr: String, - - duration_excluding_children_sec: f64, - system_stats: JsonStepSystemStats, - - children: Vec<JsonNode>, - }, - TestSuite(TestSuite), -} - -#[derive(Serialize, Deserialize)] -pub struct TestSuite { - pub metadata: TestSuiteMetadata, - pub tests: Vec<Test>, -} - -#[derive(Serialize, Deserialize)] -#[serde(tag = "kind", rename_all = "snake_case")] -pub enum TestSuiteMetadata { - CargoPackage { - crates: Vec<String>, - target: String, - host: String, - stage: u32, - }, - Compiletest { - suite: String, - mode: String, - compare_mode: Option<String>, - target: String, - host: String, - stage: u32, - }, -} - -#[derive(Serialize, Deserialize)] -pub struct Test { - pub name: String, - #[serde(flatten)] - pub outcome: TestOutcome, -} - -#[derive(Serialize, Deserialize)] -#[serde(tag = "outcome", rename_all = "snake_case")] -pub enum TestOutcome { - Passed, - Failed, - Ignored { ignore_reason: Option<String> }, -} - -#[derive(Serialize, Deserialize)] -#[serde(rename_all = "snake_case")] -pub struct JsonInvocationSystemStats { - pub cpu_threads_count: usize, - pub cpu_model: String, - - pub memory_total_bytes: u64, -} - -#[derive(Serialize, Deserialize)] -#[serde(rename_all = "snake_case")] -pub struct JsonStepSystemStats { - pub cpu_utilization_percent: f64, -} diff --git a/src/tools/build_helper/src/stage0_parser.rs b/src/tools/build_helper/src/stage0_parser.rs deleted file mode 100644 index ff05b116989..00000000000 --- a/src/tools/build_helper/src/stage0_parser.rs +++ /dev/null @@ -1,76 +0,0 @@ -use std::collections::BTreeMap; - -#[derive(Default, Clone)] -pub struct Stage0 { - pub compiler: VersionMetadata, - pub rustfmt: Option<VersionMetadata>, - pub config: Stage0Config, - pub checksums_sha256: BTreeMap<String, String>, -} - -#[derive(Default, Clone)] -pub struct VersionMetadata { - pub date: String, - pub version: String, -} - -#[derive(Default, Clone)] -pub struct Stage0Config { - pub dist_server: String, - pub artifacts_server: String, - pub artifacts_with_llvm_assertions_server: String, - pub git_merge_commit_email: String, - pub git_repository: String, - pub nightly_branch: String, -} - -pub fn parse_stage0_file() -> Stage0 { - let stage0_content = include_str!("../../../stage0"); - - let mut stage0 = Stage0::default(); - for line in stage0_content.lines() { - let line = line.trim(); - - if line.is_empty() { - continue; - } - - // Ignore comments - if line.starts_with('#') { - continue; - } - - let (key, value) = line.split_once('=').unwrap(); - - match key { - "dist_server" => stage0.config.dist_server = value.to_owned(), - "artifacts_server" => stage0.config.artifacts_server = value.to_owned(), - "artifacts_with_llvm_assertions_server" => { - stage0.config.artifacts_with_llvm_assertions_server = value.to_owned() - } - "git_merge_commit_email" => stage0.config.git_merge_commit_email = value.to_owned(), - "git_repository" => stage0.config.git_repository = value.to_owned(), - "nightly_branch" => stage0.config.nightly_branch = value.to_owned(), - - "compiler_date" => stage0.compiler.date = value.to_owned(), - "compiler_version" => stage0.compiler.version = value.to_owned(), - - "rustfmt_date" => { - stage0.rustfmt.get_or_insert(VersionMetadata::default()).date = value.to_owned(); - } - "rustfmt_version" => { - stage0.rustfmt.get_or_insert(VersionMetadata::default()).version = value.to_owned(); - } - - dist if dist.starts_with("dist") => { - stage0.checksums_sha256.insert(key.to_owned(), value.to_owned()); - } - - unsupported => { - println!("'{unsupported}' field is not supported."); - } - } - } - - stage0 -} diff --git a/src/tools/build_helper/src/util.rs b/src/tools/build_helper/src/util.rs deleted file mode 100644 index 72c05c4c48a..00000000000 --- a/src/tools/build_helper/src/util.rs +++ /dev/null @@ -1,75 +0,0 @@ -use std::fs::File; -use std::io::{BufRead, BufReader}; -use std::path::Path; -use std::process::Command; -use std::sync::OnceLock; - -/// Invokes `build_helper::util::detail_exit` with `cfg!(test)` -/// -/// This is a macro instead of a function so that it uses `cfg(test)` in the *calling* crate, not in build helper. -#[macro_export] -macro_rules! exit { - ($code:expr) => { - $crate::util::detail_exit($code, cfg!(test)); - }; -} - -/// If code is not 0 (successful exit status), exit status is 101 (rust's default error code.) -/// If `is_test` true and code is an error code, it will cause a panic. -pub fn detail_exit(code: i32, is_test: bool) -> ! { - // if in test and code is an error code, panic with status code provided - if is_test { - panic!("status code: {}", code); - } else { - // otherwise,exit with provided status code - std::process::exit(code); - } -} - -pub fn fail(s: &str) -> ! { - eprintln!("\n\n{}\n\n", s); - detail_exit(1, cfg!(test)); -} - -pub fn try_run(cmd: &mut Command, print_cmd_on_fail: bool) -> Result<(), ()> { - let status = match cmd.status() { - Ok(status) => status, - Err(e) => fail(&format!("failed to execute command: {:?}\nerror: {}", cmd, e)), - }; - if !status.success() { - if print_cmd_on_fail { - println!( - "\n\ncommand did not execute successfully: {:?}\n\ - expected success, got: {}\n\n", - cmd, status - ); - } - Err(()) - } else { - Ok(()) - } -} - -/// Returns the submodule paths from the `.gitmodules` file in the given directory. -pub fn parse_gitmodules(target_dir: &Path) -> &[String] { - static SUBMODULES_PATHS: OnceLock<Vec<String>> = OnceLock::new(); - let gitmodules = target_dir.join(".gitmodules"); - assert!(gitmodules.exists(), "'{}' file is missing.", gitmodules.display()); - - let init_submodules_paths = || { - let file = File::open(gitmodules).unwrap(); - - let mut submodules_paths = vec![]; - for line in BufReader::new(file).lines().map_while(Result::ok) { - let line = line.trim(); - if line.starts_with("path") { - let actual_path = line.split(' ').last().expect("Couldn't get value of path"); - submodules_paths.push(actual_path.to_owned()); - } - } - - submodules_paths - }; - - SUBMODULES_PATHS.get_or_init(|| init_submodules_paths()) -} diff --git a/src/tools/bump-stage0/Cargo.toml b/src/tools/bump-stage0/Cargo.toml index de5d821133d..6ee7a831839 100644 --- a/src/tools/bump-stage0/Cargo.toml +++ b/src/tools/bump-stage0/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" [dependencies] anyhow = "1.0.34" -build_helper = { path = "../build_helper" } +build_helper = { path = "../../build_helper" } curl = "0.4.38" indexmap = { version = "2.0.0", features = ["serde"] } serde = { version = "1.0.125", features = ["derive"] } diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md index 161fa630ed4..dd3124ee9a3 100644 --- a/src/tools/clippy/CHANGELOG.md +++ b/src/tools/clippy/CHANGELOG.md @@ -6071,6 +6071,7 @@ Released 2018-09-13 [`unnecessary_literal_bound`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_literal_bound [`unnecessary_literal_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_literal_unwrap [`unnecessary_map_on_constructor`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_map_on_constructor +[`unnecessary_map_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_map_or [`unnecessary_min_or_max`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_min_or_max [`unnecessary_mut_passed`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_mut_passed [`unnecessary_operation`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_operation diff --git a/src/tools/clippy/clippy_dev/src/setup/vscode.rs b/src/tools/clippy/clippy_dev/src/setup/vscode.rs index 204f4af2cf1..a37c873eed4 100644 --- a/src/tools/clippy/clippy_dev/src/setup/vscode.rs +++ b/src/tools/clippy/clippy_dev/src/setup/vscode.rs @@ -84,7 +84,7 @@ fn delete_vs_task_file(path: &Path) -> bool { /// It may fail silently. fn try_delete_vs_directory_if_empty() { let path = Path::new(VSCODE_DIR); - if path.read_dir().map_or(false, |mut iter| iter.next().is_none()) { + if path.read_dir().is_ok_and(|mut iter| iter.next().is_none()) { // The directory is empty. We just try to delete it but allow a silence // fail as an empty `.vscode` directory is still valid let _silence_result = fs::remove_dir(path); diff --git a/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs b/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs index dc5a6857089..e21853598c3 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs @@ -16,7 +16,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, item: &Item, attrs: &[Attribute]) { return; } if let Some(lint_list) = &attr.meta_item_list() { - if attr.ident().map_or(false, |ident| is_lint_level(ident.name, attr.id)) { + if attr.ident().is_some_and(|ident| is_lint_level(ident.name, attr.id)) { for lint in lint_list { match item.kind { ItemKind::Use(..) => { diff --git a/src/tools/clippy/clippy_lints/src/attrs/utils.rs b/src/tools/clippy/clippy_lints/src/attrs/utils.rs index 9b10ae83651..3bb02688bf2 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/utils.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/utils.rs @@ -50,7 +50,7 @@ fn is_relevant_block(cx: &LateContext<'_>, typeck_results: &ty::TypeckResults<'_ block .expr .as_ref() - .map_or(false, |e| is_relevant_expr(cx, typeck_results, e)), + .is_some_and(|e| is_relevant_expr(cx, typeck_results, e)), |stmt| match &stmt.kind { StmtKind::Let(_) => true, StmtKind::Expr(expr) | StmtKind::Semi(expr) => is_relevant_expr(cx, typeck_results, expr), @@ -60,7 +60,7 @@ fn is_relevant_block(cx: &LateContext<'_>, typeck_results: &ty::TypeckResults<'_ } fn is_relevant_expr(cx: &LateContext<'_>, typeck_results: &ty::TypeckResults<'_>, expr: &Expr<'_>) -> bool { - if macro_backtrace(expr.span).last().map_or(false, |macro_call| { + if macro_backtrace(expr.span).last().is_some_and(|macro_call| { is_panic(cx, macro_call.def_id) || cx.tcx.item_name(macro_call.def_id) == sym::unreachable }) { return false; diff --git a/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs b/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs index db5792188dd..7d89195eeca 100644 --- a/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs +++ b/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs @@ -60,8 +60,8 @@ fn is_impl_not_trait_with_bool_out<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) - trait_id, ) }) - .map_or(false, |assoc_item| { - let proj = Ty::new_projection_from_args(cx.tcx, assoc_item.def_id, cx.tcx.mk_args_trait(ty, [])); + .is_some_and(|assoc_item| { + let proj = Ty::new_projection(cx.tcx, assoc_item.def_id, cx.tcx.mk_args_trait(ty, [])); let nty = cx.tcx.normalize_erasing_regions(cx.param_env, proj); nty.is_bool() diff --git a/src/tools/clippy/clippy_lints/src/booleans.rs b/src/tools/clippy/clippy_lints/src/booleans.rs index 26a20bc99a0..896bd5fd03d 100644 --- a/src/tools/clippy/clippy_lints/src/booleans.rs +++ b/src/tools/clippy/clippy_lints/src/booleans.rs @@ -667,5 +667,5 @@ fn implements_ord(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { let ty = cx.typeck_results().expr_ty(expr); cx.tcx .get_diagnostic_item(sym::Ord) - .map_or(false, |id| implements_trait(cx, ty, id, &[])) + .is_some_and(|id| implements_trait(cx, ty, id, &[])) } diff --git a/src/tools/clippy/clippy_lints/src/box_default.rs b/src/tools/clippy/clippy_lints/src/box_default.rs index bf1d077fec2..a1ca23e65ff 100644 --- a/src/tools/clippy/clippy_lints/src/box_default.rs +++ b/src/tools/clippy/clippy_lints/src/box_default.rs @@ -45,7 +45,7 @@ impl LateLintPass<'_> for BoxDefault { // And that method is `new` && seg.ident.name == sym::new // And the call is that of a `Box` method - && path_def_id(cx, ty).map_or(false, |id| Some(id) == cx.tcx.lang_items().owned_box()) + && path_def_id(cx, ty).is_some_and(|id| Some(id) == cx.tcx.lang_items().owned_box()) // And the single argument to the call is another function call // This is the `T::default()` (or default equivalent) of `Box::new(T::default())` && let ExprKind::Call(arg_path, _) = arg.kind @@ -83,9 +83,9 @@ fn is_plain_default(cx: &LateContext<'_>, arg_path: &Expr<'_>) -> bool { } fn is_local_vec_expn(cx: &LateContext<'_>, expr: &Expr<'_>, ref_expr: &Expr<'_>) -> bool { - macro_backtrace(expr.span).next().map_or(false, |call| { - cx.tcx.is_diagnostic_item(sym::vec_macro, call.def_id) && call.span.eq_ctxt(ref_expr.span) - }) + macro_backtrace(expr.span) + .next() + .is_some_and(|call| cx.tcx.is_diagnostic_item(sym::vec_macro, call.def_id) && call.span.eq_ctxt(ref_expr.span)) } #[derive(Default)] diff --git a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs index abd80abffe6..332e897def7 100644 --- a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs +++ b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs @@ -159,8 +159,7 @@ pub(super) fn check<'tcx>( // The same is true if the expression encompassing the cast expression is a unary // expression or an addressof expression. let needs_block = matches!(cast_expr.kind, ExprKind::Unary(..) | ExprKind::AddrOf(..)) - || get_parent_expr(cx, expr) - .map_or(false, |e| matches!(e.kind, ExprKind::Unary(..) | ExprKind::AddrOf(..))); + || get_parent_expr(cx, expr).is_some_and(|e| matches!(e.kind, ExprKind::Unary(..) | ExprKind::AddrOf(..))); span_lint_and_sugg( cx, diff --git a/src/tools/clippy/clippy_lints/src/comparison_chain.rs b/src/tools/clippy/clippy_lints/src/comparison_chain.rs index b9baf9af248..c85e3500ebd 100644 --- a/src/tools/clippy/clippy_lints/src/comparison_chain.rs +++ b/src/tools/clippy/clippy_lints/src/comparison_chain.rs @@ -110,7 +110,7 @@ impl<'tcx> LateLintPass<'tcx> for ComparisonChain { let is_ord = cx .tcx .get_diagnostic_item(sym::Ord) - .map_or(false, |id| implements_trait(cx, ty, id, &[])); + .is_some_and(|id| implements_trait(cx, ty, id, &[])); if !is_ord { return; diff --git a/src/tools/clippy/clippy_lints/src/copies.rs b/src/tools/clippy/clippy_lints/src/copies.rs index c4afdc757d8..3ecd36d3711 100644 --- a/src/tools/clippy/clippy_lints/src/copies.rs +++ b/src/tools/clippy/clippy_lints/src/copies.rs @@ -345,7 +345,7 @@ fn eq_binding_names(s: &Stmt<'_>, names: &[(HirId, Symbol)]) -> bool { let mut i = 0usize; let mut res = true; l.pat.each_binding_or_first(&mut |_, _, _, name| { - if names.get(i).map_or(false, |&(_, n)| n == name.name) { + if names.get(i).is_some_and(|&(_, n)| n == name.name) { i += 1; } else { res = false; @@ -389,12 +389,10 @@ fn eq_stmts( let new_bindings = &moved_bindings[old_count..]; blocks .iter() - .all(|b| get_stmt(b).map_or(false, |s| eq_binding_names(s, new_bindings))) + .all(|b| get_stmt(b).is_some_and(|s| eq_binding_names(s, new_bindings))) } else { true - }) && blocks - .iter() - .all(|b| get_stmt(b).map_or(false, |s| eq.eq_stmt(s, stmt))) + }) && blocks.iter().all(|b| get_stmt(b).is_some_and(|s| eq.eq_stmt(s, stmt))) } #[expect(clippy::too_many_lines)] @@ -451,9 +449,7 @@ fn scan_block_for_eq<'tcx>( // x + 50 let expr_hash_eq = if let Some(e) = block.expr { let hash = hash_expr(cx, e); - blocks - .iter() - .all(|b| b.expr.map_or(false, |e| hash_expr(cx, e) == hash)) + blocks.iter().all(|b| b.expr.is_some_and(|e| hash_expr(cx, e) == hash)) } else { blocks.iter().all(|b| b.expr.is_none()) }; @@ -514,7 +510,7 @@ fn scan_block_for_eq<'tcx>( }); if let Some(e) = block.expr { for block in blocks { - if block.expr.map_or(false, |expr| !eq.eq_expr(expr, e)) { + if block.expr.is_some_and(|expr| !eq.eq_expr(expr, e)) { moved_locals.truncate(moved_locals_at_start); return BlockEq { start_end_eq, @@ -533,7 +529,7 @@ fn scan_block_for_eq<'tcx>( } fn check_for_warn_of_moved_symbol(cx: &LateContext<'_>, symbols: &[(HirId, Symbol)], if_expr: &Expr<'_>) -> bool { - get_enclosing_block(cx, if_expr.hir_id).map_or(false, |block| { + get_enclosing_block(cx, if_expr.hir_id).is_some_and(|block| { let ignore_span = block.span.shrink_to_lo().to(if_expr.span); symbols diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs index edb52851e0c..dff60f76b74 100644 --- a/src/tools/clippy/clippy_lints/src/declared_lints.rs +++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs @@ -481,6 +481,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::methods::UNNECESSARY_JOIN_INFO, crate::methods::UNNECESSARY_LAZY_EVALUATIONS_INFO, crate::methods::UNNECESSARY_LITERAL_UNWRAP_INFO, + crate::methods::UNNECESSARY_MAP_OR_INFO, crate::methods::UNNECESSARY_MIN_OR_MAX_INFO, crate::methods::UNNECESSARY_RESULT_MAP_OR_ELSE_INFO, crate::methods::UNNECESSARY_SORT_BY_INFO, diff --git a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs index 4808c372754..ef6b141920d 100644 --- a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs +++ b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs @@ -253,6 +253,6 @@ impl<'tcx> From<Ty<'tcx>> for ExplicitTyBound { impl<'tcx> From<Option<Ty<'tcx>>> for ExplicitTyBound { fn from(v: Option<Ty<'tcx>>) -> Self { - Self(v.map_or(false, Ty::is_numeric)) + Self(v.is_some_and(Ty::is_numeric)) } } diff --git a/src/tools/clippy/clippy_lints/src/derivable_impls.rs b/src/tools/clippy/clippy_lints/src/derivable_impls.rs index 2b6bfafe695..767dda552bc 100644 --- a/src/tools/clippy/clippy_lints/src/derivable_impls.rs +++ b/src/tools/clippy/clippy_lints/src/derivable_impls.rs @@ -81,7 +81,7 @@ fn is_path_self(e: &Expr<'_>) -> bool { fn contains_trait_object(ty: Ty<'_>) -> bool { match ty.kind() { ty::Ref(_, ty, _) => contains_trait_object(*ty), - ty::Adt(def, args) => def.is_box() && args[0].as_type().map_or(false, contains_trait_object), + ty::Adt(def, args) => def.is_box() && args[0].as_type().is_some_and(contains_trait_object), ty::Dynamic(..) => true, _ => false, } diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs index e569c4dc786..0db6a822ec0 100644 --- a/src/tools/clippy/clippy_lints/src/derive.rs +++ b/src/tools/clippy/clippy_lints/src/derive.rs @@ -327,7 +327,7 @@ fn check_copy_clone<'tcx>(cx: &LateContext<'tcx>, item: &Item<'_>, trait_ref: &h // there's a Copy impl for any instance of the adt. if !is_copy(cx, ty) { if ty_subs.non_erasable_generics().next().is_some() { - let has_copy_impl = cx.tcx.all_local_trait_impls(()).get(©_id).map_or(false, |impls| { + let has_copy_impl = cx.tcx.all_local_trait_impls(()).get(©_id).is_some_and(|impls| { impls.iter().any(|&id| { matches!(cx.tcx.type_of(id).instantiate_identity().kind(), ty::Adt(adt, _) if ty_adt.did() == adt.did()) diff --git a/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs b/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs index c9173030a55..40377dd841e 100644 --- a/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs +++ b/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs @@ -47,7 +47,7 @@ pub fn check( ), _ => (), } - if !headers.panics && panic_info.map_or(false, |el| !el.1) { + if !headers.panics && panic_info.is_some_and(|el| !el.1) { span_lint_and_note( cx, MISSING_PANICS_DOC, diff --git a/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs b/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs index c7dd7292a14..55afdbf22e1 100644 --- a/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs +++ b/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs @@ -112,7 +112,7 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef { MEM_FORGET, Cow::Owned(format!( "usage of `mem::forget` on {}", - if arg_ty.ty_adt_def().map_or(false, |def| def.has_dtor(cx.tcx)) { + if arg_ty.ty_adt_def().is_some_and(|def| def.has_dtor(cx.tcx)) { "`Drop` type" } else { "type with `Drop` fields" diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs index de10b7bf533..6c87a05ace3 100644 --- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs +++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs @@ -196,7 +196,7 @@ fn check_clousure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tc { span_lint_and_then(cx, REDUNDANT_CLOSURE, expr.span, "redundant closure", |diag| { if let Some(mut snippet) = snippet_opt(cx, callee.span) { - if path_to_local(callee).map_or(false, |l| { + if path_to_local(callee).is_some_and(|l| { // FIXME: Do we really need this `local_used_in` check? // Isn't it checking something like... `callee(callee)`? // If somehow this check is needed, add some test for it, diff --git a/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs b/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs index c2b40ae01d4..4986a311eba 100644 --- a/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs +++ b/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs @@ -87,7 +87,7 @@ fn raw_ptr_arg(cx: &LateContext<'_>, arg: &hir::Param<'_>) -> Option<HirId> { } fn check_arg(cx: &LateContext<'_>, raw_ptrs: &HirIdSet, arg: &hir::Expr<'_>) { - if path_to_local(arg).map_or(false, |id| raw_ptrs.contains(&id)) { + if path_to_local(arg).is_some_and(|id| raw_ptrs.contains(&id)) { span_lint( cx, NOT_UNSAFE_PTR_ARG_DEREF, diff --git a/src/tools/clippy/clippy_lints/src/infinite_iter.rs b/src/tools/clippy/clippy_lints/src/infinite_iter.rs index 48874d6064b..d3aade31f14 100644 --- a/src/tools/clippy/clippy_lints/src/infinite_iter.rs +++ b/src/tools/clippy/clippy_lints/src/infinite_iter.rs @@ -171,13 +171,13 @@ fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness { if let ExprKind::Path(ref qpath) = path.kind { cx.qpath_res(qpath, path.hir_id) .opt_def_id() - .map_or(false, |id| cx.tcx.is_diagnostic_item(sym::iter_repeat, id)) + .is_some_and(|id| cx.tcx.is_diagnostic_item(sym::iter_repeat, id)) .into() } else { Finite } }, - ExprKind::Struct(..) => higher::Range::hir(expr).map_or(false, |r| r.end.is_none()).into(), + ExprKind::Struct(..) => higher::Range::hir(expr).is_some_and(|r| r.end.is_none()).into(), _ => Finite, } } @@ -228,9 +228,7 @@ fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness { let not_double_ended = cx .tcx .get_diagnostic_item(sym::DoubleEndedIterator) - .map_or(false, |id| { - !implements_trait(cx, cx.typeck_results().expr_ty(receiver), id, &[]) - }); + .is_some_and(|id| !implements_trait(cx, cx.typeck_results().expr_ty(receiver), id, &[])); if not_double_ended { return is_infinite(cx, receiver); } diff --git a/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs b/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs index dd90e2a6e94..6363f717a5c 100644 --- a/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs +++ b/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs @@ -309,8 +309,8 @@ fn check_enum_start(cx: &LateContext<'_>, item_name: &str, variant: &Variant<'_> let item_name_chars = item_name.chars().count(); if count_match_start(item_name, name).char_count == item_name_chars - && name.chars().nth(item_name_chars).map_or(false, |c| !c.is_lowercase()) - && name.chars().nth(item_name_chars + 1).map_or(false, |c| !c.is_numeric()) + && name.chars().nth(item_name_chars).is_some_and(|c| !c.is_lowercase()) + && name.chars().nth(item_name_chars + 1).is_some_and(|c| !c.is_numeric()) { span_lint_hir( cx, diff --git a/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs b/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs index b19b348c743..25105817ad9 100644 --- a/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs +++ b/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs @@ -75,7 +75,7 @@ fn check_sig(cx: &LateContext<'_>, name: Symbol, sig: &FnSig<'_>, fn_id: LocalDe if cx .tcx .get_diagnostic_item(sym::Iterator) - .map_or(false, |iter_id| !implements_trait(cx, ret_ty, iter_id, &[])) + .is_some_and(|iter_id| !implements_trait(cx, ret_ty, iter_id, &[])) { span_lint( cx, diff --git a/src/tools/clippy/clippy_lints/src/large_const_arrays.rs b/src/tools/clippy/clippy_lints/src/large_const_arrays.rs index aa8b4d88d2f..c5a2760234f 100644 --- a/src/tools/clippy/clippy_lints/src/large_const_arrays.rs +++ b/src/tools/clippy/clippy_lints/src/large_const_arrays.rs @@ -56,7 +56,8 @@ impl<'tcx> LateLintPass<'tcx> for LargeConstArrays { && !item.span.from_expansion() && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity() && let ty::Array(element_type, cst) = ty.kind() - && let Ok((_, ty::ValTree::Leaf(element_count))) = cst.eval_valtree(cx.tcx, ParamEnv::empty(), item.span) + && let Some((ty::ValTree::Leaf(element_count), _)) = cx.tcx + .try_normalize_erasing_regions(ParamEnv::empty(), *cst).unwrap_or(*cst).try_to_valtree() && let element_count = element_count.to_target_usize(cx.tcx) && let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes()) && u128::from(self.maximum_allowed_size) < u128::from(element_count) * u128::from(element_size) diff --git a/src/tools/clippy/clippy_lints/src/large_include_file.rs b/src/tools/clippy/clippy_lints/src/large_include_file.rs index ab3d19f89c3..4f22931a4de 100644 --- a/src/tools/clippy/clippy_lints/src/large_include_file.rs +++ b/src/tools/clippy/clippy_lints/src/large_include_file.rs @@ -94,6 +94,8 @@ impl LateLintPass<'_> for LargeIncludeFile { // Currently, rustc limits the usage of macro at the top-level of attributes, // so we don't need to recurse into each level. && let AttrKind::Normal(ref normal) = attr.kind + && let Some(doc) = attr.doc_str() + && doc.as_str().len() as u64 > self.max_file_size && let AttrArgs::Eq(_, AttrArgsEq::Hir(ref meta)) = normal.item.args && !attr.span.contains(meta.span) // Since the `include_str` is already expanded at this point, we can only take the diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs index b7887ef76a5..3ea758e176f 100644 --- a/src/tools/clippy/clippy_lints/src/len_zero.rs +++ b/src/tools/clippy/clippy_lints/src/len_zero.rs @@ -622,7 +622,7 @@ fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { let ty = &cx.typeck_results().expr_ty(expr).peel_refs(); match ty.kind() { - ty::Dynamic(tt, ..) => tt.principal().map_or(false, |principal| { + ty::Dynamic(tt, ..) => tt.principal().is_some_and(|principal| { let is_empty = sym!(is_empty); cx.tcx .associated_items(principal.def_id()) diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs index d55be2b036a..ce0e1a24a7b 100644 --- a/src/tools/clippy/clippy_lints/src/lifetimes.rs +++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs @@ -737,7 +737,7 @@ fn elision_suggestions( suggestions.extend( usages .iter() - .filter(|usage| named_lifetime(usage).map_or(false, |id| elidable_lts.contains(&id))) + .filter(|usage| named_lifetime(usage).is_some_and(|id| elidable_lts.contains(&id))) .map(|usage| { match cx.tcx.parent_hir_node(usage.hir_id) { Node::Ty(Ty { diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_find.rs b/src/tools/clippy/clippy_lints/src/loops/manual_find.rs index bfe2e68b5d1..1721f569541 100644 --- a/src/tools/clippy/clippy_lints/src/loops/manual_find.rs +++ b/src/tools/clippy/clippy_lints/src/loops/manual_find.rs @@ -58,7 +58,7 @@ pub(super) fn check<'tcx>( .tcx .lang_items() .copy_trait() - .map_or(false, |id| implements_trait(cx, ty, id, &[])) + .is_some_and(|id| implements_trait(cx, ty, id, &[])) { snippet.push_str( &format!( diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs b/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs index af089451759..701567a7d84 100644 --- a/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs +++ b/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs @@ -416,7 +416,7 @@ fn get_assignments<'a, 'tcx>( .chain(*expr) .filter(move |e| { if let ExprKind::AssignOp(_, place, _) = e.kind { - path_to_local(place).map_or(false, |id| { + path_to_local(place).is_some_and(|id| { !loop_counters .iter() // skip the first item which should be `StartKind::Range` diff --git a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs index 094b1947324..39e5e140b7a 100644 --- a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs +++ b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs @@ -126,7 +126,7 @@ impl BreakAfterExprVisitor { break_after_expr: false, }; - get_enclosing_block(cx, hir_id).map_or(false, |block| { + get_enclosing_block(cx, hir_id).is_some_and(|block| { visitor.visit_block(block); visitor.break_after_expr }) diff --git a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs index d255fea3af2..951ebc9caef 100644 --- a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs +++ b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs @@ -50,7 +50,7 @@ pub(super) fn check<'tcx>( .tcx .lang_items() .clone_trait() - .map_or(false, |id| implements_trait(cx, ty, id, &[])) + .is_some_and(|id| implements_trait(cx, ty, id, &[])) { // Make sure that the push does not involve possibly mutating values match pushed_item.kind { diff --git a/src/tools/clippy/clippy_lints/src/loops/utils.rs b/src/tools/clippy/clippy_lints/src/loops/utils.rs index c4c504e1ae4..51fde5288ab 100644 --- a/src/tools/clippy/clippy_lints/src/loops/utils.rs +++ b/src/tools/clippy/clippy_lints/src/loops/utils.rs @@ -256,9 +256,10 @@ fn is_conditional(expr: &Expr<'_>) -> bool { /// If `arg` was the argument to a `for` loop, return the "cleanest" way of writing the /// actual `Iterator` that the loop uses. pub(super) fn make_iterator_snippet(cx: &LateContext<'_>, arg: &Expr<'_>, applic_ref: &mut Applicability) -> String { - let impls_iterator = cx.tcx.get_diagnostic_item(sym::Iterator).map_or(false, |id| { - implements_trait(cx, cx.typeck_results().expr_ty(arg), id, &[]) - }); + let impls_iterator = cx + .tcx + .get_diagnostic_item(sym::Iterator) + .is_some_and(|id| implements_trait(cx, cx.typeck_results().expr_ty(arg), id, &[])); if impls_iterator { format!( "{}", diff --git a/src/tools/clippy/clippy_lints/src/manual_clamp.rs b/src/tools/clippy/clippy_lints/src/manual_clamp.rs index fd66cacdfe9..016ec7320a6 100644 --- a/src/tools/clippy/clippy_lints/src/manual_clamp.rs +++ b/src/tools/clippy/clippy_lints/src/manual_clamp.rs @@ -226,7 +226,7 @@ impl TypeClampability { } else if cx .tcx .get_diagnostic_item(sym::Ord) - .map_or(false, |id| implements_trait(cx, ty, id, &[])) + .is_some_and(|id| implements_trait(cx, ty, id, &[])) { Some(TypeClampability::Ord) } else { diff --git a/src/tools/clippy/clippy_lints/src/manual_strip.rs b/src/tools/clippy/clippy_lints/src/manual_strip.rs index 828c5a3f6ff..3f401eff6bd 100644 --- a/src/tools/clippy/clippy_lints/src/manual_strip.rs +++ b/src/tools/clippy/clippy_lints/src/manual_strip.rs @@ -162,9 +162,9 @@ fn eq_pattern_length<'tcx>(cx: &LateContext<'tcx>, pattern: &Expr<'_>, expr: &'t .. }) = expr.kind { - constant_length(cx, pattern).map_or(false, |length| *n == length) + constant_length(cx, pattern).is_some_and(|length| *n == length) } else { - len_arg(cx, expr).map_or(false, |arg| eq_expr_value(cx, pattern, arg)) + len_arg(cx, expr).is_some_and(|arg| eq_expr_value(cx, pattern, arg)) } } diff --git a/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs b/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs index 6d62b530ae7..47472ab831f 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs @@ -74,7 +74,7 @@ where && b0 != b1 && (first_guard.is_none() || iter.len() == 0) && first_attrs.is_empty() - && iter.all(|arm| find_bool_lit(&arm.2.kind).map_or(false, |b| b == b0) && arm.3.is_none() && arm.0.is_empty()) + && iter.all(|arm| find_bool_lit(&arm.2.kind).is_some_and(|b| b == b0) && arm.3.is_none() && arm.0.is_empty()) { if let Some(last_pat) = last_pat_opt { if !is_wild(last_pat) { diff --git a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs index ca45ed6ea59..264458a86ef 100644 --- a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs +++ b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs @@ -447,7 +447,7 @@ fn is_pat_variant(cx: &LateContext<'_>, pat: &Pat<'_>, path: &QPath<'_>, expecte .tcx .lang_items() .get(expected_lang_item) - .map_or(false, |expected_id| cx.tcx.parent(id) == expected_id), + .is_some_and(|expected_id| cx.tcx.parent(id) == expected_id), Item::Diag(expected_ty, expected_variant) => { let ty = cx.typeck_results().pat_ty(pat); diff --git a/src/tools/clippy/clippy_lints/src/matches/single_match.rs b/src/tools/clippy/clippy_lints/src/matches/single_match.rs index 2aea25b5f12..95a4bf6f60d 100644 --- a/src/tools/clippy/clippy_lints/src/matches/single_match.rs +++ b/src/tools/clippy/clippy_lints/src/matches/single_match.rs @@ -175,7 +175,7 @@ impl<'tcx> Visitor<'tcx> for PatVisitor<'tcx> { if matches!(pat.kind, PatKind::Binding(..)) { ControlFlow::Break(()) } else { - self.has_enum |= self.typeck.pat_ty(pat).ty_adt_def().map_or(false, AdtDef::is_enum); + self.has_enum |= self.typeck.pat_ty(pat).ty_adt_def().is_some_and(AdtDef::is_enum); walk_pat(self, pat) } } diff --git a/src/tools/clippy/clippy_lints/src/matches/try_err.rs b/src/tools/clippy/clippy_lints/src/matches/try_err.rs index c7e1b70d19e..6c02207af49 100644 --- a/src/tools/clippy/clippy_lints/src/matches/try_err.rs +++ b/src/tools/clippy/clippy_lints/src/matches/try_err.rs @@ -58,7 +58,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, scrutine let span = hygiene::walk_chain(err_arg.span, try_arg.span.ctxt()); let mut applicability = Applicability::MachineApplicable; let origin_snippet = snippet_with_applicability(cx, span, "_", &mut applicability); - let ret_prefix = if get_parent_expr(cx, expr).map_or(false, |e| matches!(e.kind, ExprKind::Ret(_))) { + let ret_prefix = if get_parent_expr(cx, expr).is_some_and(|e| matches!(e.kind, ExprKind::Ret(_))) { "" // already returns } else { "return " diff --git a/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs index c288dbdabe9..6dc48c26ba9 100644 --- a/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs +++ b/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs @@ -83,7 +83,7 @@ pub(super) fn check<'tcx>( hir::ExprKind::MethodCall(..) => { cx.typeck_results() .type_dependent_def_id(arg.hir_id) - .map_or(false, |method_id| { + .is_some_and(|method_id| { matches!( cx.tcx.fn_sig(method_id).instantiate_identity().output().skip_binder().kind(), ty::Ref(re, ..) if re.is_static() diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_next.rs b/src/tools/clippy/clippy_lints/src/methods/filter_next.rs index e697ba656f5..6c1a14fc882 100644 --- a/src/tools/clippy/clippy_lints/src/methods/filter_next.rs +++ b/src/tools/clippy/clippy_lints/src/methods/filter_next.rs @@ -32,9 +32,10 @@ pub(super) fn check<'tcx>( filter_arg: &'tcx hir::Expr<'_>, ) { // lint if caller of `.filter().next()` is an Iterator - let recv_impls_iterator = cx.tcx.get_diagnostic_item(sym::Iterator).map_or(false, |id| { - implements_trait(cx, cx.typeck_results().expr_ty(recv), id, &[]) - }); + let recv_impls_iterator = cx + .tcx + .get_diagnostic_item(sym::Iterator) + .is_some_and(|id| implements_trait(cx, cx.typeck_results().expr_ty(recv), id, &[])); if recv_impls_iterator { let msg = "called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling \ `.find(..)` instead"; diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_next_back.rs b/src/tools/clippy/clippy_lints/src/methods/manual_next_back.rs index 5f3fec53827..9a03559b223 100644 --- a/src/tools/clippy/clippy_lints/src/methods/manual_next_back.rs +++ b/src/tools/clippy/clippy_lints/src/methods/manual_next_back.rs @@ -19,9 +19,7 @@ pub(super) fn check<'tcx>( if cx .tcx .get_diagnostic_item(sym::DoubleEndedIterator) - .map_or(false, |double_ended_iterator| { - implements_trait(cx, rev_recv_ty, double_ended_iterator, &[]) - }) + .is_some_and(|double_ended_iterator| implements_trait(cx, rev_recv_ty, double_ended_iterator, &[])) && is_trait_method(cx, rev_call, sym::Iterator) && is_trait_method(cx, expr, sym::Iterator) { diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_str_repeat.rs b/src/tools/clippy/clippy_lints/src/methods/manual_str_repeat.rs index 61e74369cb0..098721dc046 100644 --- a/src/tools/clippy/clippy_lints/src/methods/manual_str_repeat.rs +++ b/src/tools/clippy/clippy_lints/src/methods/manual_str_repeat.rs @@ -36,8 +36,8 @@ fn parse_repeat_arg(cx: &LateContext<'_>, e: &Expr<'_>) -> Option<RepeatKind> { } else { let ty = cx.typeck_results().expr_ty(e); if is_type_lang_item(cx, ty, LangItem::String) - || (is_type_lang_item(cx, ty, LangItem::OwnedBox) && get_ty_param(ty).map_or(false, Ty::is_str)) - || (is_type_diagnostic_item(cx, ty, sym::Cow) && get_ty_param(ty).map_or(false, Ty::is_str)) + || (is_type_lang_item(cx, ty, LangItem::OwnedBox) && get_ty_param(ty).is_some_and(Ty::is_str)) + || (is_type_diagnostic_item(cx, ty, sym::Cow) && get_ty_param(ty).is_some_and(Ty::is_str)) { Some(RepeatKind::String) } else { diff --git a/src/tools/clippy/clippy_lints/src/methods/map_clone.rs b/src/tools/clippy/clippy_lints/src/methods/map_clone.rs index 515d4a11ed5..d5594b21db5 100644 --- a/src/tools/clippy/clippy_lints/src/methods/map_clone.rs +++ b/src/tools/clippy/clippy_lints/src/methods/map_clone.rs @@ -70,7 +70,7 @@ pub(super) fn check(cx: &LateContext<'_>, e: &hir::Expr<'_>, recv: &hir::Expr<'_ if ident_eq(name, obj) && method.ident.name == sym::clone && let Some(fn_id) = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id) && let Some(trait_id) = cx.tcx.trait_of_item(fn_id) - && cx.tcx.lang_items().clone_trait().map_or(false, |id| id == trait_id) + && cx.tcx.lang_items().clone_trait() == Some(trait_id) // no autoderefs && !cx.typeck_results().expr_adjustments(obj).iter() .any(|a| matches!(a.kind, Adjust::Deref(Some(..)))) diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs index b1809796355..795e041ffd9 100644 --- a/src/tools/clippy/clippy_lints/src/methods/mod.rs +++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs @@ -121,6 +121,7 @@ mod unnecessary_iter_cloned; mod unnecessary_join; mod unnecessary_lazy_eval; mod unnecessary_literal_unwrap; +mod unnecessary_map_or; mod unnecessary_min_or_max; mod unnecessary_result_map_or_else; mod unnecessary_sort_by; @@ -4101,6 +4102,33 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does + /// Converts some constructs mapping an Enum value for equality comparison. + /// + /// ### Why is this bad? + /// Calls such as `opt.map_or(false, |val| val == 5)` are needlessly long and cumbersome, + /// and can be reduced to, for example, `opt == Some(5)` assuming `opt` implements `PartialEq`. + /// This lint offers readability and conciseness improvements. + /// + /// ### Example + /// ```no_run + /// pub fn a(x: Option<i32>) -> bool { + /// x.map_or(false, |n| n == 5) + /// } + /// ``` + /// Use instead: + /// ```no_run + /// pub fn a(x: Option<i32>) -> bool { + /// x == Some(5) + /// } + /// ``` + #[clippy::version = "1.75.0"] + pub UNNECESSARY_MAP_OR, + style, + "reduce unnecessary pattern matching for constructs that implement `PartialEq`" +} + +declare_clippy_lint! { + /// ### What it does /// Checks if an iterator is used to check if a string is ascii. /// /// ### Why is this bad? @@ -4417,6 +4445,7 @@ impl_lint_pass!(Methods => [ NEEDLESS_AS_BYTES, MAP_ALL_ANY_IDENTITY, MAP_WITH_UNUSED_ARGUMENT_OVER_RANGES, + UNNECESSARY_MAP_OR, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -4950,6 +4979,7 @@ impl Methods { option_map_or_none::check(cx, expr, recv, def, map); manual_ok_or::check(cx, expr, recv, def, map); option_map_or_err_ok::check(cx, expr, recv, def, map); + unnecessary_map_or::check(cx, expr, recv, def, map, &self.msrv); }, ("map_or_else", [def, map]) => { result_map_or_else_none::check(cx, expr, recv, def, map); @@ -5343,7 +5373,7 @@ impl SelfKind { boxed_ty == parent_ty } else if is_type_diagnostic_item(cx, ty, sym::Rc) || is_type_diagnostic_item(cx, ty, sym::Arc) { if let ty::Adt(_, args) = ty.kind() { - args.types().next().map_or(false, |t| t == parent_ty) + args.types().next() == Some(parent_ty) } else { false } diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs index 055107068ae..9c41528e647 100644 --- a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs +++ b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs @@ -193,7 +193,7 @@ fn check_collect_into_intoiterator<'tcx>( /// Checks if the given method call matches the expected signature of `([&[mut]] self) -> bool` fn is_is_empty_sig(cx: &LateContext<'_>, call_id: HirId) -> bool { - cx.typeck_results().type_dependent_def_id(call_id).map_or(false, |id| { + cx.typeck_results().type_dependent_def_id(call_id).is_some_and(|id| { let sig = cx.tcx.fn_sig(id).instantiate_identity().skip_binder(); sig.inputs().len() == 1 && sig.output().is_bool() }) diff --git a/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs b/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs index 389e02056b2..998bdee0157 100644 --- a/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs +++ b/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs @@ -45,7 +45,7 @@ pub(super) fn check( hir::ExprKind::Path(ref expr_qpath) => { cx.qpath_res(expr_qpath, map_arg.hir_id) .opt_def_id() - .map_or(false, |fun_def_id| { + .is_some_and(|fun_def_id| { cx.tcx.is_diagnostic_item(sym::deref_method, fun_def_id) || cx.tcx.is_diagnostic_item(sym::deref_mut_method, fun_def_id) || deref_aliases diff --git a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs index b685a466b72..6b39b753885 100644 --- a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs +++ b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs @@ -59,9 +59,7 @@ pub(super) fn check<'tcx>( let output_ty = cx.tcx.fn_sig(def_id).instantiate(cx.tcx, args).skip_binder().output(); cx.tcx .get_diagnostic_item(sym::Default) - .map_or(false, |default_trait_id| { - implements_trait(cx, output_ty, default_trait_id, &[]) - }) + .is_some_and(|default_trait_id| implements_trait(cx, output_ty, default_trait_id, &[])) } else { false } diff --git a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs index a2a7de905ca..1cee28e1986 100644 --- a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs +++ b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs @@ -348,7 +348,7 @@ fn parse_iter_usage<'tcx>( && cx .typeck_results() .type_dependent_def_id(e.hir_id) - .map_or(false, |id| is_diag_item_method(cx, id, sym::Option)) => + .is_some_and(|id| is_diag_item_method(cx, id, sym::Option)) => { (Some(UnwrapKind::Unwrap), e.span) }, diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_map_or.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_map_or.rs new file mode 100644 index 00000000000..adc27cd437f --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_map_or.rs @@ -0,0 +1,131 @@ +use std::borrow::Cow; + +use clippy_config::msrvs::{self, Msrv}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::eager_or_lazy::switch_to_eager_eval; +use clippy_utils::source::snippet_opt; +use clippy_utils::sugg::{Sugg, make_binop}; +use clippy_utils::ty::{get_type_diagnostic_name, implements_trait}; +use clippy_utils::visitors::is_local_used; +use clippy_utils::{is_from_proc_macro, path_to_local_id}; +use rustc_ast::LitKind::Bool; +use rustc_errors::Applicability; +use rustc_hir::{BinOpKind, Expr, ExprKind, PatKind}; +use rustc_lint::LateContext; +use rustc_span::sym; + +use super::UNNECESSARY_MAP_OR; + +pub(super) enum Variant { + Ok, + Some, +} +impl Variant { + pub fn variant_name(&self) -> &'static str { + match self { + Variant::Ok => "Ok", + Variant::Some => "Some", + } + } + + pub fn method_name(&self) -> &'static str { + match self { + Variant::Ok => "is_ok_and", + Variant::Some => "is_some_and", + } + } +} + +pub(super) fn check<'a>( + cx: &LateContext<'a>, + expr: &Expr<'a>, + recv: &Expr<'_>, + def: &Expr<'_>, + map: &Expr<'_>, + msrv: &Msrv, +) { + let ExprKind::Lit(def_kind) = def.kind else { + return; + }; + + let recv_ty = cx.typeck_results().expr_ty(recv); + + let Bool(def_bool) = def_kind.node else { + return; + }; + + let variant = match get_type_diagnostic_name(cx, recv_ty) { + Some(sym::Option) => Variant::Some, + Some(sym::Result) => Variant::Ok, + Some(_) | None => return, + }; + + let (sugg, method) = if let ExprKind::Closure(map_closure) = map.kind + && let closure_body = cx.tcx.hir().body(map_closure.body) + && let closure_body_value = closure_body.value.peel_blocks() + && let ExprKind::Binary(op, l, r) = closure_body_value.kind + && let Some(param) = closure_body.params.first() + && let PatKind::Binding(_, hir_id, _, _) = param.pat.kind + // checking that map_or is one of the following: + // .map_or(false, |x| x == y) + // .map_or(false, |x| y == x) - swapped comparison + // .map_or(true, |x| x != y) + // .map_or(true, |x| y != x) - swapped comparison + && ((BinOpKind::Eq == op.node && !def_bool) || (BinOpKind::Ne == op.node && def_bool)) + && let non_binding_location = if path_to_local_id(l, hir_id) { r } else { l } + && switch_to_eager_eval(cx, non_binding_location) + // xor, because if its both then thats a strange edge case and + // we can just ignore it, since by default clippy will error on this + && (path_to_local_id(l, hir_id) ^ path_to_local_id(r, hir_id)) + && !is_local_used(cx, non_binding_location, hir_id) + && let typeck_results = cx.typeck_results() + && typeck_results.expr_ty(l) == typeck_results.expr_ty(r) + && let Some(partial_eq) = cx.tcx.get_diagnostic_item(sym::PartialEq) + && implements_trait(cx, recv_ty, partial_eq, &[recv_ty.into()]) + { + let wrap = variant.variant_name(); + + // we may need to add parens around the suggestion + // in case the parent expression has additional method calls, + // since for example `Some(5).map_or(false, |x| x == 5).then(|| 1)` + // being converted to `Some(5) == Some(5).then(|| 1)` isnt + // the same thing + + let inner_non_binding = Sugg::NonParen(Cow::Owned(format!( + "{wrap}({})", + Sugg::hir(cx, non_binding_location, "") + ))); + + let binop = make_binop(op.node, &Sugg::hir(cx, recv, ".."), &inner_non_binding) + .maybe_par() + .into_string(); + + (binop, "a standard comparison") + } else if !def_bool + && msrv.meets(msrvs::OPTION_RESULT_IS_VARIANT_AND) + && let Some(recv_callsite) = snippet_opt(cx, recv.span.source_callsite()) + && let Some(span_callsite) = snippet_opt(cx, map.span.source_callsite()) + { + let suggested_name = variant.method_name(); + ( + format!("{recv_callsite}.{suggested_name}({span_callsite})",), + suggested_name, + ) + } else { + return; + }; + + if is_from_proc_macro(cx, expr) { + return; + } + + span_lint_and_sugg( + cx, + UNNECESSARY_MAP_OR, + expr.span, + "this `map_or` is redundant", + format!("use {method} instead"), + sugg, + Applicability::MaybeIncorrect, + ); +} diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs index 6911da69b94..603916e06c9 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs @@ -166,9 +166,10 @@ fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg: &Exp }, )) = &left_expr.kind && left_name == left_ident - && cx.tcx.get_diagnostic_item(sym::Ord).map_or(false, |id| { - implements_trait(cx, cx.typeck_results().expr_ty(left_expr), id, &[]) - }) + && cx + .tcx + .get_diagnostic_item(sym::Ord) + .is_some_and(|id| implements_trait(cx, cx.typeck_results().expr_ty(left_expr), id, &[])) { return Some(LintTrigger::Sort(SortDetection { vec_name })); } diff --git a/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs b/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs index c309e778116..82313257e5c 100644 --- a/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs +++ b/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs @@ -124,7 +124,7 @@ fn is_calling_clone(cx: &LateContext<'_>, arg: &hir::Expr<'_>) -> bool { && let Some(fn_id) = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id) && let Some(trait_id) = cx.tcx.trait_of_item(fn_id) // We check it's the `Clone` trait. - && cx.tcx.lang_items().clone_trait().map_or(false, |id| id == trait_id) + && cx.tcx.lang_items().clone_trait().is_some_and(|id| id == trait_id) // no autoderefs && !cx.typeck_results().expr_adjustments(obj).iter() .any(|a| matches!(a.kind, Adjust::Deref(Some(..)))) diff --git a/src/tools/clippy/clippy_lints/src/misc_early/mod.rs b/src/tools/clippy/clippy_lints/src/misc_early/mod.rs index 4cba13a05c2..37d7427f9a5 100644 --- a/src/tools/clippy/clippy_lints/src/misc_early/mod.rs +++ b/src/tools/clippy/clippy_lints/src/misc_early/mod.rs @@ -427,7 +427,7 @@ impl MiscEarlyLints { // See <https://github.com/rust-lang/rust-clippy/issues/4507> for a regression. // FIXME: Find a better way to detect those cases. let lit_snip = match snippet_opt(cx, span) { - Some(snip) if snip.chars().next().map_or(false, |c| c.is_ascii_digit()) => snip, + Some(snip) if snip.chars().next().is_some_and(|c| c.is_ascii_digit()) => snip, _ => return, }; diff --git a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs index f7fa31d83aa..c1424b9f1dc 100644 --- a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs +++ b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs @@ -134,9 +134,11 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrowsForGenericArgs<'tcx> { } fn check_body_post(&mut self, cx: &LateContext<'tcx>, body: &Body<'_>) { - if self.possible_borrowers.last().map_or(false, |&(local_def_id, _)| { - local_def_id == cx.tcx.hir().body_owner_def_id(body.id()) - }) { + if self + .possible_borrowers + .last() + .is_some_and(|&(local_def_id, _)| local_def_id == cx.tcx.hir().body_owner_def_id(body.id())) + { self.possible_borrowers.pop(); } } @@ -232,7 +234,7 @@ fn needless_borrow_count<'tcx>( let mut check_reference_and_referent = |reference: &Expr<'tcx>, referent: &Expr<'tcx>| { if let ExprKind::Field(base, _) = &referent.kind { let base_ty = cx.typeck_results().expr_ty(base); - if drop_trait_def_id.map_or(false, |id| implements_trait(cx, base_ty, id, &[])) { + if drop_trait_def_id.is_some_and(|id| implements_trait(cx, base_ty, id, &[])) { return false; } } diff --git a/src/tools/clippy/clippy_lints/src/needless_continue.rs b/src/tools/clippy/clippy_lints/src/needless_continue.rs index c4836772933..c48232f9905 100644 --- a/src/tools/clippy/clippy_lints/src/needless_continue.rs +++ b/src/tools/clippy/clippy_lints/src/needless_continue.rs @@ -153,7 +153,7 @@ fn needless_continue_in_else(else_expr: &ast::Expr, label: Option<&ast::Label>) } fn is_first_block_stmt_continue(block: &ast::Block, label: Option<&ast::Label>) -> bool { - block.stmts.first().map_or(false, |stmt| match stmt.kind { + block.stmts.first().is_some_and(|stmt| match stmt.kind { ast::StmtKind::Semi(ref e) | ast::StmtKind::Expr(ref e) => { if let ast::ExprKind::Continue(ref l) = e.kind { compare_labels(label, l.as_ref()) @@ -390,7 +390,7 @@ fn check_and_warn(cx: &EarlyContext<'_>, expr: &ast::Expr) { #[must_use] fn erode_from_back(s: &str) -> String { let mut ret = s.to_string(); - while ret.pop().map_or(false, |c| c != '}') {} + while ret.pop().is_some_and(|c| c != '}') {} while let Some(c) = ret.pop() { if !c.is_whitespace() { ret.push(c); diff --git a/src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs b/src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs index a13391a5945..83f7d931969 100644 --- a/src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs +++ b/src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs @@ -88,7 +88,7 @@ fn is_offending_macro(cx: &EarlyContext<'_>, span: Span, mac_braces: &MacroBrace || span .macro_backtrace() .last() - .map_or(false, |e| e.macro_def_id.map_or(false, DefId::is_local)) + .is_some_and(|e| e.macro_def_id.is_some_and(DefId::is_local)) }; let span_call_site = span.ctxt().outer_expn_data().call_site; if let ExpnKind::Macro(MacroKind::Bang, mac_name) = span.ctxt().outer_expn_data().kind diff --git a/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs b/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs index 372128ac16f..13b3d240700 100644 --- a/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs +++ b/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs @@ -290,7 +290,7 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion { Some((Node::Expr(parent), child_id)) => match parent.kind { // Recursive call. Track which index the parameter is used in. ExprKind::Call(callee, args) - if path_def_id(cx, callee).map_or(false, |id| { + if path_def_id(cx, callee).is_some_and(|id| { id == param.fn_id && has_matching_args(param.fn_kind, typeck.node_args(callee.hir_id)) }) => { @@ -300,7 +300,7 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion { return; }, ExprKind::MethodCall(_, receiver, args, _) - if typeck.type_dependent_def_id(parent.hir_id).map_or(false, |id| { + if typeck.type_dependent_def_id(parent.hir_id).is_some_and(|id| { id == param.fn_id && has_matching_args(param.fn_kind, typeck.node_args(parent.hir_id)) }) => { diff --git a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs index 8b9f899d82d..65ef56fd211 100644 --- a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs +++ b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs @@ -325,7 +325,7 @@ impl ArithmeticSideEffects { fn should_skip_expr<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &hir::Expr<'tcx>) -> bool { is_lint_allowed(cx, ARITHMETIC_SIDE_EFFECTS, expr.hir_id) || self.expr_span.is_some() - || self.const_span.map_or(false, |sp| sp.contains(expr.span)) + || self.const_span.is_some_and(|sp| sp.contains(expr.span)) } } diff --git a/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs b/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs index 208b20a7a06..b0d872e98fd 100644 --- a/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs +++ b/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs @@ -42,14 +42,12 @@ fn check_op(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool) if typeck .type_dependent_def_id(expr.hir_id) .and_then(|id| cx.tcx.trait_of_item(id)) - .map_or(false, |id| { - matches!(cx.tcx.get_diagnostic_name(id), Some(sym::ToString | sym::ToOwned)) - }) => + .is_some_and(|id| matches!(cx.tcx.get_diagnostic_name(id), Some(sym::ToString | sym::ToOwned))) => { (arg, arg.span) }, ExprKind::Call(path, [arg]) - if path_def_id(cx, path).map_or(false, |did| { + if path_def_id(cx, path).is_some_and(|did| { if cx.tcx.is_diagnostic_item(sym::from_str_method, did) { true } else if cx.tcx.is_diagnostic_item(sym::from_fn, did) { diff --git a/src/tools/clippy/clippy_lints/src/operators/identity_op.rs b/src/tools/clippy/clippy_lints/src/operators/identity_op.rs index 830be50c8ba..1c2d6e90fc9 100644 --- a/src/tools/clippy/clippy_lints/src/operators/identity_op.rs +++ b/src/tools/clippy/clippy_lints/src/operators/identity_op.rs @@ -42,83 +42,43 @@ pub(crate) fn check<'tcx>( match op { BinOpKind::Add | BinOpKind::BitOr | BinOpKind::BitXor => { - let _ = check_op( - cx, - left, - 0, - expr.span, - peeled_right_span, - needs_parenthesis(cx, expr, right), - right_is_coerced_to_value, - ) || check_op( - cx, - right, - 0, - expr.span, - peeled_left_span, - Parens::Unneeded, - left_is_coerced_to_value, - ); + if is_redundant_op(cx, left, 0) { + let paren = needs_parenthesis(cx, expr, right); + span_ineffective_operation(cx, expr.span, peeled_right_span, paren, right_is_coerced_to_value); + } else if is_redundant_op(cx, right, 0) { + let paren = needs_parenthesis(cx, expr, left); + span_ineffective_operation(cx, expr.span, peeled_left_span, paren, left_is_coerced_to_value); + } }, BinOpKind::Shl | BinOpKind::Shr | BinOpKind::Sub => { - let _ = check_op( - cx, - right, - 0, - expr.span, - peeled_left_span, - Parens::Unneeded, - left_is_coerced_to_value, - ); + if is_redundant_op(cx, right, 0) { + let paren = needs_parenthesis(cx, expr, left); + span_ineffective_operation(cx, expr.span, peeled_left_span, paren, left_is_coerced_to_value); + } }, BinOpKind::Mul => { - let _ = check_op( - cx, - left, - 1, - expr.span, - peeled_right_span, - needs_parenthesis(cx, expr, right), - right_is_coerced_to_value, - ) || check_op( - cx, - right, - 1, - expr.span, - peeled_left_span, - Parens::Unneeded, - left_is_coerced_to_value, - ); + if is_redundant_op(cx, left, 1) { + let paren = needs_parenthesis(cx, expr, right); + span_ineffective_operation(cx, expr.span, peeled_right_span, paren, right_is_coerced_to_value); + } else if is_redundant_op(cx, right, 1) { + let paren = needs_parenthesis(cx, expr, left); + span_ineffective_operation(cx, expr.span, peeled_left_span, paren, left_is_coerced_to_value); + } }, BinOpKind::Div => { - let _ = check_op( - cx, - right, - 1, - expr.span, - peeled_left_span, - Parens::Unneeded, - left_is_coerced_to_value, - ); + if is_redundant_op(cx, right, 1) { + let paren = needs_parenthesis(cx, expr, left); + span_ineffective_operation(cx, expr.span, peeled_left_span, paren, left_is_coerced_to_value); + } }, BinOpKind::BitAnd => { - let _ = check_op( - cx, - left, - -1, - expr.span, - peeled_right_span, - needs_parenthesis(cx, expr, right), - right_is_coerced_to_value, - ) || check_op( - cx, - right, - -1, - expr.span, - peeled_left_span, - Parens::Unneeded, - left_is_coerced_to_value, - ); + if is_redundant_op(cx, left, -1) { + let paren = needs_parenthesis(cx, expr, right); + span_ineffective_operation(cx, expr.span, peeled_right_span, paren, right_is_coerced_to_value); + } else if is_redundant_op(cx, right, -1) { + let paren = needs_parenthesis(cx, expr, left); + span_ineffective_operation(cx, expr.span, peeled_left_span, paren, left_is_coerced_to_value); + } }, BinOpKind::Rem => check_remainder(cx, left, right, expr.span, left.span), _ => (), @@ -138,43 +98,70 @@ enum Parens { Unneeded, } -/// Checks if `left op right` needs parenthesis when reduced to `right` +/// Checks if a binary expression needs parenthesis when reduced to just its +/// right or left child. +/// +/// e.g. `-(x + y + 0)` cannot be reduced to `-x + y`, as the behavior changes silently. +/// e.g. `1u64 + ((x + y + 0i32) as u64)` cannot be reduced to `1u64 + x + y as u64`, since +/// the the cast expression will not apply to the same expression. /// e.g. `0 + if b { 1 } else { 2 } + if b { 3 } else { 4 }` cannot be reduced /// to `if b { 1 } else { 2 } + if b { 3 } else { 4 }` where the `if` could be -/// interpreted as a statement +/// interpreted as a statement. The same behavior happens for `match`, `loop`, +/// and blocks. +/// e.g. `2 * (0 + { a })` can be reduced to `2 * { a }` without the need for parenthesis, +/// but `1 * ({ a } + 4)` cannot be reduced to `{ a } + 4`, as a block at the start of a line +/// will be interpreted as a statement instead of an expression. /// -/// See #8724 -fn needs_parenthesis(cx: &LateContext<'_>, binary: &Expr<'_>, right: &Expr<'_>) -> Parens { - match right.kind { +/// See #8724, #13470 +fn needs_parenthesis(cx: &LateContext<'_>, binary: &Expr<'_>, child: &Expr<'_>) -> Parens { + match child.kind { ExprKind::Binary(_, lhs, _) | ExprKind::Cast(lhs, _) => { - // ensure we're checking against the leftmost expression of `right` - // - // ~~~ `lhs` - // 0 + {4} * 2 - // ~~~~~~~ `right` - return needs_parenthesis(cx, binary, lhs); + // For casts and binary expressions, we want to add parenthesis if + // the parent HIR node is an expression, or if the parent HIR node + // is a Block or Stmt, and the new left hand side would need + // parenthesis be treated as a statement rather than an expression. + if let Some((_, parent)) = cx.tcx.hir().parent_iter(binary.hir_id).next() { + match parent { + Node::Expr(_) => return Parens::Needed, + Node::Block(_) | Node::Stmt(_) => { + // ensure we're checking against the leftmost expression of `child` + // + // ~~~~~~~~~~~ `binary` + // ~~~ `lhs` + // 0 + {4} * 2 + // ~~~~~~~ `child` + return needs_parenthesis(cx, binary, lhs); + }, + _ => return Parens::Unneeded, + } + } + }, + ExprKind::If(..) | ExprKind::Match(..) | ExprKind::Block(..) | ExprKind::Loop(..) => { + // For if, match, block, and loop expressions, we want to add parenthesis if + // the closest ancestor node that is not an expression is a block or statement. + // This would mean that the rustfix suggestion will appear at the start of a line, which causes + // these expressions to be interpreted as statements if they do not have parenthesis. + let mut prev_id = binary.hir_id; + for (_, parent) in cx.tcx.hir().parent_iter(binary.hir_id) { + if let Node::Expr(expr) = parent + && let ExprKind::Binary(_, lhs, _) | ExprKind::Cast(lhs, _) | ExprKind::Unary(_, lhs) = expr.kind + && lhs.hir_id == prev_id + { + // keep going until we find a node that encompasses left of `binary` + prev_id = expr.hir_id; + continue; + } + + match parent { + Node::Block(_) | Node::Stmt(_) => return Parens::Needed, + _ => return Parens::Unneeded, + }; + } + }, + _ => { + return Parens::Unneeded; }, - ExprKind::If(..) | ExprKind::Match(..) | ExprKind::Block(..) | ExprKind::Loop(..) => {}, - _ => return Parens::Unneeded, - } - - let mut prev_id = binary.hir_id; - for (_, node) in cx.tcx.hir().parent_iter(binary.hir_id) { - if let Node::Expr(expr) = node - && let ExprKind::Binary(_, lhs, _) | ExprKind::Cast(lhs, _) = expr.kind - && lhs.hir_id == prev_id - { - // keep going until we find a node that encompasses left of `binary` - prev_id = expr.hir_id; - continue; - } - - match node { - Node::Block(_) | Node::Stmt(_) => break, - _ => return Parens::Unneeded, - }; } - Parens::Needed } @@ -199,7 +186,7 @@ fn check_remainder(cx: &LateContext<'_>, left: &Expr<'_>, right: &Expr<'_>, span } } -fn check_op(cx: &LateContext<'_>, e: &Expr<'_>, m: i8, span: Span, arg: Span, parens: Parens, is_erased: bool) -> bool { +fn is_redundant_op(cx: &LateContext<'_>, e: &Expr<'_>, m: i8) -> bool { if let Some(Constant::Int(v)) = ConstEvalCtxt::new(cx).eval_simple(e).map(Constant::peel_refs) { let check = match *cx.typeck_results().expr_ty(e).peel_refs().kind() { ty::Int(ity) => unsext(cx.tcx, -1_i128, ity), @@ -212,7 +199,6 @@ fn check_op(cx: &LateContext<'_>, e: &Expr<'_>, m: i8, span: Span, arg: Span, pa 1 => v == 1, _ => unreachable!(), } { - span_ineffective_operation(cx, span, arg, parens, is_erased); return true; } } diff --git a/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs b/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs index 565294bb40a..d369978b8be 100644 --- a/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs +++ b/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs @@ -14,7 +14,7 @@ pub struct Context { } impl Context { fn skip_expr(&mut self, e: &hir::Expr<'_>) -> bool { - self.expr_id.is_some() || self.const_span.map_or(false, |span| span.contains(e.span)) + self.expr_id.is_some() || self.const_span.is_some_and(|span| span.contains(e.span)) } pub fn check_binary<'tcx>( diff --git a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs index 1bddfab39c6..b2089487a9f 100644 --- a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs +++ b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs @@ -192,7 +192,7 @@ impl PassByRefOrValue { continue; } } - let value_type = if fn_body.and_then(|body| body.params.get(index)).map_or(false, is_self) { + let value_type = if fn_body.and_then(|body| body.params.get(index)).is_some_and(is_self) { "self".into() } else { snippet(cx, decl_ty.span, "_").into() diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs index a548c6ef3b1..ecc095f3859 100644 --- a/src/tools/clippy/clippy_lints/src/ptr.rs +++ b/src/tools/clippy/clippy_lints/src/ptr.rs @@ -727,9 +727,8 @@ fn get_ref_lm<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> Option<(&'tcx Lifetime, Mutabili fn is_null_path(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { if let ExprKind::Call(pathexp, []) = expr.kind { - path_def_id(cx, pathexp).map_or(false, |id| { - matches!(cx.tcx.get_diagnostic_name(id), Some(sym::ptr_null | sym::ptr_null_mut)) - }) + path_def_id(cx, pathexp) + .is_some_and(|id| matches!(cx.tcx.get_diagnostic_name(id), Some(sym::ptr_null | sym::ptr_null_mut))) } else { false } diff --git a/src/tools/clippy/clippy_lints/src/question_mark.rs b/src/tools/clippy/clippy_lints/src/question_mark.rs index cb374fcf20e..a00fd01a62e 100644 --- a/src/tools/clippy/clippy_lints/src/question_mark.rs +++ b/src/tools/clippy/clippy_lints/src/question_mark.rs @@ -8,18 +8,18 @@ use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; use clippy_utils::{ eq_expr_value, higher, is_else_clause, is_in_const_context, is_lint_allowed, is_path_lang_item, is_res_lang_ctor, - pat_and_expr_can_be_question_mark, path_to_local, path_to_local_id, peel_blocks, peel_blocks_with_stmt, - span_contains_comment, + pat_and_expr_can_be_question_mark, path_res, path_to_local, path_to_local_id, peel_blocks, peel_blocks_with_stmt, + span_contains_cfg, span_contains_comment, }; use rustc_errors::Applicability; use rustc_hir::LangItem::{self, OptionNone, OptionSome, ResultErr, ResultOk}; use rustc_hir::def::Res; use rustc_hir::{ - BindingMode, Block, Body, ByRef, Expr, ExprKind, LetStmt, Mutability, Node, PatKind, PathSegment, QPath, Stmt, - StmtKind, + Arm, BindingMode, Block, Body, ByRef, Expr, ExprKind, FnRetTy, HirId, LetStmt, MatchSource, Mutability, Node, Pat, + PatKind, PathSegment, QPath, Stmt, StmtKind, }; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::Ty; +use rustc_middle::ty::{self, Ty}; use rustc_session::impl_lint_pass; use rustc_span::sym; use rustc_span::symbol::Symbol; @@ -58,6 +58,9 @@ pub struct QuestionMark { /// if it is greater than zero. /// As for why we need this in the first place: <https://github.com/rust-lang/rust-clippy/issues/8628> try_block_depth_stack: Vec<u32>, + /// Keeps track of the number of inferred return type closures we are inside, to avoid problems + /// with the `Err(x.into())` expansion being ambiguious. + inferred_ret_closure_stack: u16, } impl_lint_pass!(QuestionMark => [QUESTION_MARK, MANUAL_LET_ELSE]); @@ -68,6 +71,7 @@ impl QuestionMark { msrv: conf.msrv.clone(), matches_behaviour: conf.matches_for_let_else, try_block_depth_stack: Vec::new(), + inferred_ret_closure_stack: 0, } } } @@ -125,7 +129,7 @@ fn check_let_some_else_return_none(cx: &LateContext<'_>, stmt: &Stmt<'_>) { cx.tcx .lang_items() .try_trait() - .map_or(false, |did| implements_trait(cx, init_ty, did, &[])) + .is_some_and(|did| implements_trait(cx, init_ty, did, &[])) } if let StmtKind::Let(LetStmt { @@ -271,6 +275,135 @@ fn check_is_none_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr: &Ex } } +#[derive(Clone, Copy, Debug)] +enum TryMode { + Result, + Option, +} + +fn find_try_mode<'tcx>(cx: &LateContext<'tcx>, scrutinee: &Expr<'tcx>) -> Option<TryMode> { + let scrutinee_ty = cx.typeck_results().expr_ty_adjusted(scrutinee); + let ty::Adt(scrutinee_adt_def, _) = scrutinee_ty.kind() else { + return None; + }; + + match cx.tcx.get_diagnostic_name(scrutinee_adt_def.did())? { + sym::Result => Some(TryMode::Result), + sym::Option => Some(TryMode::Option), + _ => None, + } +} + +// Check that `pat` is `{ctor_lang_item}(val)`, returning `val`. +fn extract_ctor_call<'a, 'tcx>( + cx: &LateContext<'tcx>, + expected_ctor: LangItem, + pat: &'a Pat<'tcx>, +) -> Option<&'a Pat<'tcx>> { + if let PatKind::TupleStruct(variant_path, [val_binding], _) = &pat.kind + && is_res_lang_ctor(cx, cx.qpath_res(variant_path, pat.hir_id), expected_ctor) + { + Some(val_binding) + } else { + None + } +} + +// Extracts the local ID of a plain `val` pattern. +fn extract_binding_pat(pat: &Pat<'_>) -> Option<HirId> { + if let PatKind::Binding(BindingMode::NONE, binding, _, None) = pat.kind { + Some(binding) + } else { + None + } +} + +fn check_arm_is_some_or_ok<'tcx>(cx: &LateContext<'tcx>, mode: TryMode, arm: &Arm<'tcx>) -> bool { + let happy_ctor = match mode { + TryMode::Result => ResultOk, + TryMode::Option => OptionSome, + }; + + // Check for `Ok(val)` or `Some(val)` + if arm.guard.is_none() + && let Some(val_binding) = extract_ctor_call(cx, happy_ctor, arm.pat) + // Extract out `val` + && let Some(binding) = extract_binding_pat(val_binding) + // Check body is just `=> val` + && path_to_local_id(peel_blocks(arm.body), binding) + { + true + } else { + false + } +} + +fn check_arm_is_none_or_err<'tcx>(cx: &LateContext<'tcx>, mode: TryMode, arm: &Arm<'tcx>) -> bool { + if arm.guard.is_some() { + return false; + } + + let arm_body = peel_blocks(arm.body); + match mode { + TryMode::Result => { + // Check that pat is Err(val) + if let Some(ok_pat) = extract_ctor_call(cx, ResultErr, arm.pat) + && let Some(ok_val) = extract_binding_pat(ok_pat) + // check `=> return Err(...)` + && let ExprKind::Ret(Some(wrapped_ret_expr)) = arm_body.kind + && let ExprKind::Call(ok_ctor, [ret_expr]) = wrapped_ret_expr.kind + && is_res_lang_ctor(cx, path_res(cx, ok_ctor), ResultErr) + // check `...` is `val` from binding + && path_to_local_id(ret_expr, ok_val) + { + true + } else { + false + } + }, + TryMode::Option => { + // Check the pat is `None` + if is_res_lang_ctor(cx, path_res(cx, arm.pat), OptionNone) + // Check `=> return None` + && let ExprKind::Ret(Some(ret_expr)) = arm_body.kind + && is_res_lang_ctor(cx, path_res(cx, ret_expr), OptionNone) + && !ret_expr.span.from_expansion() + { + true + } else { + false + } + }, + } +} + +fn check_arms_are_try<'tcx>(cx: &LateContext<'tcx>, mode: TryMode, arm1: &Arm<'tcx>, arm2: &Arm<'tcx>) -> bool { + (check_arm_is_some_or_ok(cx, mode, arm1) && check_arm_is_none_or_err(cx, mode, arm2)) + || (check_arm_is_some_or_ok(cx, mode, arm2) && check_arm_is_none_or_err(cx, mode, arm1)) +} + +fn check_if_try_match<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { + if let ExprKind::Match(scrutinee, [arm1, arm2], MatchSource::Normal | MatchSource::Postfix) = expr.kind + && !expr.span.from_expansion() + && let Some(mode) = find_try_mode(cx, scrutinee) + && !span_contains_cfg(cx, expr.span) + && check_arms_are_try(cx, mode, arm1, arm2) + { + let mut applicability = Applicability::MachineApplicable; + let snippet = snippet_with_applicability(cx, scrutinee.span.source_callsite(), "..", &mut applicability); + + span_lint_and_sugg( + cx, + QUESTION_MARK, + expr.span, + "this `match` expression can be replaced with `?`", + "try instead", + snippet.into_owned() + "?", + applicability, + ); + } +} + fn check_if_let_some_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { if let Some(higher::IfLet { let_pat, @@ -339,6 +472,17 @@ fn is_try_block(cx: &LateContext<'_>, bl: &Block<'_>) -> bool { } } +fn is_inferred_ret_closure(expr: &Expr<'_>) -> bool { + let ExprKind::Closure(closure) = expr.kind else { + return false; + }; + + match closure.fn_decl.output { + FnRetTy::Return(ret_ty) => ret_ty.is_suggestable_infer_ty(), + FnRetTy::DefaultReturn(_) => true, + } +} + impl<'tcx> LateLintPass<'tcx> for QuestionMark { fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) { if !is_lint_allowed(cx, QUESTION_MARK_USED, stmt.hir_id) { @@ -350,11 +494,27 @@ impl<'tcx> LateLintPass<'tcx> for QuestionMark { } self.check_manual_let_else(cx, stmt); } + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + if is_inferred_ret_closure(expr) { + self.inferred_ret_closure_stack += 1; + return; + } + if !self.inside_try_block() && !is_in_const_context(cx) && is_lint_allowed(cx, QUESTION_MARK_USED, expr.hir_id) { check_is_none_or_err_and_early_return(cx, expr); check_if_let_some_or_err_and_early_return(cx, expr); + + if self.inferred_ret_closure_stack == 0 { + check_if_try_match(cx, expr); + } + } + } + + fn check_expr_post(&mut self, _: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { + if is_inferred_ret_closure(expr) { + self.inferred_ret_closure_stack -= 1; } } diff --git a/src/tools/clippy/clippy_lints/src/redundant_slicing.rs b/src/tools/clippy/clippy_lints/src/redundant_slicing.rs index 030df535c35..dc66fb28fa8 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_slicing.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_slicing.rs @@ -85,7 +85,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantSlicing { let (expr_ty, expr_ref_count) = peel_middle_ty_refs(cx.typeck_results().expr_ty(expr)); let (indexed_ty, indexed_ref_count) = peel_middle_ty_refs(cx.typeck_results().expr_ty(indexed)); let parent_expr = get_parent_expr(cx, expr); - let needs_parens_for_prefix = parent_expr.map_or(false, |parent| parent.precedence().order() > PREC_PREFIX); + let needs_parens_for_prefix = parent_expr.is_some_and(|parent| parent.precedence().order() > PREC_PREFIX); if expr_ty == indexed_ty { if expr_ref_count > indexed_ref_count { @@ -107,7 +107,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantSlicing { kind: ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, _), .. }) - ) || cx.typeck_results().expr_adjustments(expr).first().map_or(false, |a| { + ) || cx.typeck_results().expr_adjustments(expr).first().is_some_and(|a| { matches!( a.kind, Adjust::Borrow(AutoBorrow::Ref(AutoBorrowMutability::Mut { .. })) diff --git a/src/tools/clippy/clippy_lints/src/swap.rs b/src/tools/clippy/clippy_lints/src/swap.rs index 23362506cca..78f0b7d121c 100644 --- a/src/tools/clippy/clippy_lints/src/swap.rs +++ b/src/tools/clippy/clippy_lints/src/swap.rs @@ -412,9 +412,7 @@ impl<'tcx> IndexBinding<'_, 'tcx> { } Self::is_used_slice_indexed(lhs, idx_ident) || Self::is_used_slice_indexed(rhs, idx_ident) }, - ExprKind::Path(QPath::Resolved(_, path)) => { - path.segments.first().map_or(false, |idx| idx.ident == idx_ident) - }, + ExprKind::Path(QPath::Resolved(_, path)) => path.segments.first().is_some_and(|idx| idx.ident == idx_ident), _ => false, } } diff --git a/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs b/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs index eb7ffbbe360..bde88ab61ad 100644 --- a/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs +++ b/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs @@ -51,8 +51,7 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, lt: &Lifetime, m format!("&{ltopt}({inner_snippet})") }, TyKind::Path(qpath) - if get_bounds_if_impl_trait(cx, qpath, inner.hir_id) - .map_or(false, |bounds| bounds.len() > 1) => + if get_bounds_if_impl_trait(cx, qpath, inner.hir_id).is_some_and(|bounds| bounds.len() > 1) => { format!("&{ltopt}({inner_snippet})") }, diff --git a/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs b/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs index 1a1284ce9c4..6eef582b4b2 100644 --- a/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs +++ b/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs @@ -38,7 +38,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, local: &'tcx LetStmt<'_>) { return; } - if (local.ty.map_or(false, |ty| !matches!(ty.kind, TyKind::Infer)) + if (local.ty.is_some_and(|ty| !matches!(ty.kind, TyKind::Infer)) || matches!(local.pat.kind, PatKind::Tuple([], ddpos) if ddpos.as_opt_usize().is_none())) && expr_needs_inferred_result(cx, init) { diff --git a/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs b/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs index 91dff5a9523..cbc6885ae5d 100644 --- a/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs +++ b/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs @@ -98,7 +98,7 @@ impl VecPushSearcher { needs_mut |= cx.typeck_results().expr_ty_adjusted(last_place).ref_mutability() == Some(Mutability::Mut) || get_parent_expr(cx, last_place) - .map_or(false, |e| matches!(e.kind, ExprKind::AddrOf(_, Mutability::Mut, _))); + .is_some_and(|e| matches!(e.kind, ExprKind::AddrOf(_, Mutability::Mut, _))); }, ExprKind::MethodCall(_, recv, ..) if recv.hir_id == e.hir_id diff --git a/src/tools/clippy/clippy_lints/src/write.rs b/src/tools/clippy/clippy_lints/src/write.rs index 1dd46ed5a89..a42ddcdae35 100644 --- a/src/tools/clippy/clippy_lints/src/write.rs +++ b/src/tools/clippy/clippy_lints/src/write.rs @@ -295,7 +295,7 @@ impl<'tcx> LateLintPass<'tcx> for Write { .opts .crate_name .as_ref() - .map_or(false, |crate_name| crate_name == "build_script_build"); + .is_some_and(|crate_name| crate_name == "build_script_build"); let allowed_in_tests = self.allow_print_in_tests && is_in_test(cx.tcx, expr.hir_id); match diag_name { diff --git a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs index 75169e05734..3269bf758ac 100644 --- a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs +++ b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs @@ -51,7 +51,7 @@ fn span_matches_pat(sess: &Session, span: Span, start_pat: Pat, end_pat: Pat) -> return false; }; let end = span.hi() - pos.sf.start_pos; - src.get(pos.pos.0 as usize..end.0 as usize).map_or(false, |s| { + src.get(pos.pos.0 as usize..end.0 as usize).is_some_and(|s| { // Spans can be wrapped in a mixture or parenthesis, whitespace, and trailing commas. let start_str = s.trim_start_matches(|c: char| c.is_whitespace() || c == '('); let end_str = s.trim_end_matches(|c: char| c.is_whitespace() || c == ')' || c == ','); @@ -60,13 +60,13 @@ fn span_matches_pat(sess: &Session, span: Span, start_pat: Pat, end_pat: Pat) -> Pat::MultiStr(texts) => texts.iter().any(|s| start_str.starts_with(s)), Pat::OwnedMultiStr(texts) => texts.iter().any(|s| start_str.starts_with(s)), Pat::Sym(sym) => start_str.starts_with(sym.as_str()), - Pat::Num => start_str.as_bytes().first().map_or(false, u8::is_ascii_digit), + Pat::Num => start_str.as_bytes().first().is_some_and(u8::is_ascii_digit), } && match end_pat { Pat::Str(text) => end_str.ends_with(text), Pat::MultiStr(texts) => texts.iter().any(|s| end_str.ends_with(s)), Pat::OwnedMultiStr(texts) => texts.iter().any(|s| end_str.ends_with(s)), Pat::Sym(sym) => end_str.ends_with(sym.as_str()), - Pat::Num => end_str.as_bytes().last().map_or(false, u8::is_ascii_hexdigit), + Pat::Num => end_str.as_bytes().last().is_some_and(u8::is_ascii_hexdigit), }) }) } diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index cb69f8e5a0e..c73ab4bfa68 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -258,7 +258,7 @@ impl HirEqInterExpr<'_, '_, '_> { } fn should_ignore(&mut self, expr: &Expr<'_>) -> bool { - macro_backtrace(expr.span).last().map_or(false, |macro_call| { + macro_backtrace(expr.span).last().is_some_and(|macro_call| { matches!( &self.inner.cx.tcx.get_diagnostic_name(macro_call.def_id), Some(sym::todo_macro | sym::unimplemented_macro) @@ -322,7 +322,7 @@ impl HirEqInterExpr<'_, '_, '_> { (&ExprKind::Block(l, _), &ExprKind::Block(r, _)) => self.eq_block(l, r), (&ExprKind::Binary(l_op, ll, lr), &ExprKind::Binary(r_op, rl, rr)) => { l_op.node == r_op.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr) - || swap_binop(l_op.node, ll, lr).map_or(false, |(l_op, ll, lr)| { + || swap_binop(l_op.node, ll, lr).is_some_and(|(l_op, ll, lr)| { l_op == r_op.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr) }) }, @@ -444,7 +444,7 @@ impl HirEqInterExpr<'_, '_, '_> { ) => false, }; (is_eq && (!self.should_ignore(left) || !self.should_ignore(right))) - || self.inner.expr_fallback.as_mut().map_or(false, |f| f(left, right)) + || self.inner.expr_fallback.as_mut().is_some_and(|f| f(left, right)) } fn eq_exprs(&mut self, left: &[Expr<'_>], right: &[Expr<'_>]) -> bool { @@ -724,7 +724,7 @@ fn swap_binop<'a>( /// `eq_fn`. pub fn both<X>(l: Option<&X>, r: Option<&X>, mut eq_fn: impl FnMut(&X, &X) -> bool) -> bool { l.as_ref() - .map_or_else(|| r.is_none(), |x| r.as_ref().map_or(false, |y| eq_fn(x, y))) + .map_or_else(|| r.is_none(), |x| r.as_ref().is_some_and(|y| eq_fn(x, y))) } /// Checks if two slices are equal as per `eq_fn`. diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 50d334acf18..19316a90683 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -342,10 +342,9 @@ pub fn is_ty_alias(qpath: &QPath<'_>) -> bool { /// Checks if the method call given in `expr` belongs to the given trait. /// This is a deprecated function, consider using [`is_trait_method`]. pub fn match_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, path: &[&str]) -> bool { - cx.typeck_results() - .type_dependent_def_id(expr.hir_id) - .and_then(|defid| cx.tcx.trait_of_item(defid)) - .map_or(false, |trt_id| match_def_path(cx, trt_id, path)) + let def_id = cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap(); + let trt_id = cx.tcx.trait_of_item(def_id); + trt_id.is_some_and(|trt_id| match_def_path(cx, trt_id, path)) } /// Checks if the given method call expression calls an inherent method. @@ -379,7 +378,7 @@ pub fn is_diag_trait_item(cx: &LateContext<'_>, def_id: DefId, diag_item: Symbol pub fn is_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, diag_item: Symbol) -> bool { cx.typeck_results() .type_dependent_def_id(expr.hir_id) - .map_or(false, |did| is_diag_trait_item(cx, did, diag_item)) + .is_some_and(|did| is_diag_trait_item(cx, did, diag_item)) } /// Checks if the `def_id` belongs to a function that is part of a trait impl. @@ -406,7 +405,7 @@ pub fn is_trait_item(cx: &LateContext<'_>, expr: &Expr<'_>, diag_item: Symbol) - if let ExprKind::Path(ref qpath) = expr.kind { cx.qpath_res(qpath, expr.hir_id) .opt_def_id() - .map_or(false, |def_id| is_diag_trait_item(cx, def_id, diag_item)) + .is_some_and(|def_id| is_diag_trait_item(cx, def_id, diag_item)) } else { false } @@ -466,13 +465,13 @@ pub fn match_qpath(path: &QPath<'_>, segments: &[&str]) -> bool { /// /// Please use `is_path_diagnostic_item` if the target is a diagnostic item. pub fn is_expr_path_def_path(cx: &LateContext<'_>, expr: &Expr<'_>, segments: &[&str]) -> bool { - path_def_id(cx, expr).map_or(false, |id| match_def_path(cx, id, segments)) + path_def_id(cx, expr).is_some_and(|id| match_def_path(cx, id, segments)) } /// If `maybe_path` is a path node which resolves to an item, resolves it to a `DefId` and checks if /// it matches the given lang item. pub fn is_path_lang_item<'tcx>(cx: &LateContext<'_>, maybe_path: &impl MaybePath<'tcx>, lang_item: LangItem) -> bool { - path_def_id(cx, maybe_path).map_or(false, |id| cx.tcx.lang_items().get(lang_item) == Some(id)) + path_def_id(cx, maybe_path).is_some_and(|id| cx.tcx.lang_items().get(lang_item) == Some(id)) } /// If `maybe_path` is a path node which resolves to an item, resolves it to a `DefId` and checks if @@ -482,7 +481,7 @@ pub fn is_path_diagnostic_item<'tcx>( maybe_path: &impl MaybePath<'tcx>, diag_item: Symbol, ) -> bool { - path_def_id(cx, maybe_path).map_or(false, |id| cx.tcx.is_diagnostic_item(diag_item, id)) + path_def_id(cx, maybe_path).is_some_and(|id| cx.tcx.is_diagnostic_item(diag_item, id)) } /// THIS METHOD IS DEPRECATED. Matches a `Path` against a slice of segment string literals. @@ -1315,7 +1314,7 @@ pub fn method_chain_args<'a>(expr: &'a Expr<'_>, methods: &[&str]) -> Option<Vec pub fn is_entrypoint_fn(cx: &LateContext<'_>, def_id: DefId) -> bool { cx.tcx .entry_fn(()) - .map_or(false, |(entry_fn_def_id, _)| def_id == entry_fn_def_id) + .is_some_and(|(entry_fn_def_id, _)| def_id == entry_fn_def_id) } /// Returns `true` if the expression is in the program's `#[panic_handler]`. @@ -1753,8 +1752,8 @@ pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool { match pat.kind { PatKind::Wild | PatKind::Never => false, // If `!` typechecked then the type is empty, so not refutable. - PatKind::Binding(_, _, _, pat) => pat.map_or(false, |pat| is_refutable(cx, pat)), - PatKind::Box(pat) | PatKind::Deref(pat) | PatKind::Ref(pat, _) => is_refutable(cx, pat), + PatKind::Binding(_, _, _, pat) => pat.is_some_and(|pat| is_refutable(cx, pat)), + PatKind::Box(pat) | PatKind::Ref(pat, _) => is_refutable(cx, pat), PatKind::Path(ref qpath) => is_enum_variant(cx, qpath, pat.hir_id), PatKind::Or(pats) => { // TODO: should be the honest check, that pats is exhaustive set @@ -1778,7 +1777,7 @@ pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool { }, } }, - PatKind::Lit(..) | PatKind::Range(..) | PatKind::Err(_) => true, + PatKind::Lit(..) | PatKind::Range(..) | PatKind::Err(_) | PatKind::Deref(_) => true, } } @@ -2021,7 +2020,7 @@ pub fn match_libc_symbol(cx: &LateContext<'_>, did: DefId, name: &str) -> bool { let path = cx.get_def_path(did); // libc is meant to be used as a flat list of names, but they're all actually defined in different // modules based on the target platform. Ignore everything but crate name and the item name. - path.first().map_or(false, |s| s.as_str() == "libc") && path.last().map_or(false, |s| s.as_str() == name) + path.first().is_some_and(|s| s.as_str() == "libc") && path.last().is_some_and(|s| s.as_str() == name) } /// Returns the list of condition expressions and the list of blocks in a @@ -2104,7 +2103,7 @@ pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { _ => None, }; - did.map_or(false, |did| cx.tcx.has_attr(did, sym::must_use)) + did.is_some_and(|did| cx.tcx.has_attr(did, sym::must_use)) } /// Checks if a function's body represents the identity function. Looks for bodies of the form: @@ -2211,7 +2210,7 @@ pub fn is_expr_untyped_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) pub fn is_expr_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { match expr.kind { ExprKind::Closure(&Closure { body, .. }) => is_body_identity_function(cx, cx.tcx.hir().body(body)), - _ => path_def_id(cx, expr).map_or(false, |id| cx.tcx.is_diagnostic_item(sym::convert_identity, id)), + _ => path_def_id(cx, expr).is_some_and(|id| cx.tcx.is_diagnostic_item(sym::convert_identity, id)), } } diff --git a/src/tools/clippy/clippy_utils/src/numeric_literal.rs b/src/tools/clippy/clippy_utils/src/numeric_literal.rs index c5a34160e3d..2c49df9d807 100644 --- a/src/tools/clippy/clippy_utils/src/numeric_literal.rs +++ b/src/tools/clippy/clippy_utils/src/numeric_literal.rs @@ -53,7 +53,7 @@ impl<'a> NumericLiteral<'a> { .trim_start() .chars() .next() - .map_or(false, |c| c.is_ascii_digit()) + .is_some_and(|c| c.is_ascii_digit()) { let (unsuffixed, suffix) = split_suffix(src, lit_kind); let float = matches!(lit_kind, LitKind::Float(..)); diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index 666ec8df930..971f8eeb1b3 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -393,12 +393,8 @@ fn is_stable_const_fn(tcx: TyCtxt<'_>, def_id: DefId, msrv: &Msrv) -> bool { msrv.meets(const_stab_rust_version) } else { - // Unstable const fn, check if the feature is enabled. We need both the regular stability - // feature and (if set) the const stability feature to const-call this function. - let stab = tcx.lookup_stability(def_id); - let is_enabled = stab.is_some_and(|s| s.is_stable() || tcx.features().enabled(s.feature)) - && const_stab.feature.is_none_or(|f| tcx.features().enabled(f)); - is_enabled && msrv.current().is_none() + // Unstable const fn, check if the feature is enabled. + tcx.features().enabled(const_stab.feature) && msrv.current().is_none() } }) } diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs index 3255c51d009..25ebe879192 100644 --- a/src/tools/clippy/clippy_utils/src/sugg.rs +++ b/src/tools/clippy/clippy_utils/src/sugg.rs @@ -905,7 +905,7 @@ impl<'tcx> DerefDelegate<'_, 'tcx> { _ => return false, }; - ty.map_or(false, |ty| matches!(ty.kind(), ty::Ref(_, inner, _) if inner.is_ref())) + ty.is_some_and(|ty| matches!(ty.kind(), ty::Ref(_, inner, _) if inner.is_ref())) } } diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs index ce1a20e0066..770cd9c3786 100644 --- a/src/tools/clippy/clippy_utils/src/ty.rs +++ b/src/tools/clippy/clippy_utils/src/ty.rs @@ -45,7 +45,7 @@ pub fn is_copy<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { pub fn has_debug_impl<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { cx.tcx .get_diagnostic_item(sym::Debug) - .map_or(false, |debug| implements_trait(cx, ty, debug, &[])) + .is_some_and(|debug| implements_trait(cx, ty, debug, &[])) } /// Checks whether a type can be partially moved. @@ -487,7 +487,7 @@ pub fn needs_ordered_drop<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { .tcx .lang_items() .drop_trait() - .map_or(false, |id| implements_trait(cx, ty, id, &[])) + .is_some_and(|id| implements_trait(cx, ty, id, &[])) { // This type doesn't implement drop, so no side effects here. // Check if any component type has any. @@ -718,7 +718,7 @@ pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'t { let output = bounds .projection_bounds() - .find(|p| lang_items.fn_once_output().map_or(false, |id| id == p.item_def_id())) + .find(|p| lang_items.fn_once_output().is_some_and(|id| id == p.item_def_id())) .map(|p| p.map_bound(|p| p.term.expect_type())); Some(ExprFnSig::Trait(bound.map_bound(|b| b.args.type_at(0)), output, None)) }, @@ -753,7 +753,7 @@ fn sig_from_bounds<'tcx>( && p.self_ty() == ty => { let i = pred.kind().rebind(p.trait_ref.args.type_at(1)); - if inputs.map_or(false, |inputs| i != inputs) { + if inputs.is_some_and(|inputs| i != inputs) { // Multiple different fn trait impls. Is this even allowed? return None; } @@ -794,7 +794,7 @@ fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: AliasTy<'tcx>) -> Option { let i = pred.kind().rebind(p.trait_ref.args.type_at(1)); - if inputs.map_or(false, |inputs| inputs != i) { + if inputs.is_some_and(|inputs| inputs != i) { // Multiple different fn trait impls. Is this even allowed? return None; } @@ -1291,7 +1291,7 @@ pub fn normalize_with_regions<'tcx>(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx> /// Checks if the type is `core::mem::ManuallyDrop<_>` pub fn is_manually_drop(ty: Ty<'_>) -> bool { - ty.ty_adt_def().map_or(false, AdtDef::is_manually_drop) + ty.ty_adt_def().is_some_and(AdtDef::is_manually_drop) } /// Returns the deref chain of a type, starting with the type itself. diff --git a/src/tools/clippy/clippy_utils/src/visitors.rs b/src/tools/clippy/clippy_utils/src/visitors.rs index 8f5ec185bf1..a79be5ca7d4 100644 --- a/src/tools/clippy/clippy_utils/src/visitors.rs +++ b/src/tools/clippy/clippy_utils/src/visitors.rs @@ -344,13 +344,13 @@ pub fn is_const_evaluatable<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> .cx .qpath_res(p, hir_id) .opt_def_id() - .map_or(false, |id| self.cx.tcx.is_const_fn(id)) => {}, + .is_some_and(|id| self.cx.tcx.is_const_fn(id)) => {}, ExprKind::MethodCall(..) if self .cx .typeck_results() .type_dependent_def_id(e.hir_id) - .map_or(false, |id| self.cx.tcx.is_const_fn(id)) => {}, + .is_some_and(|id| self.cx.tcx.is_const_fn(id)) => {}, ExprKind::Binary(_, lhs, rhs) if self.cx.typeck_results().expr_ty(lhs).peel_refs().is_primitive_ty() && self.cx.typeck_results().expr_ty(rhs).peel_refs().is_primitive_ty() => {}, @@ -426,9 +426,7 @@ pub fn is_expr_unsafe<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> bool { .cx .typeck_results() .type_dependent_def_id(e.hir_id) - .map_or(false, |id| { - self.cx.tcx.fn_sig(id).skip_binder().safety() == Safety::Unsafe - }) => + .is_some_and(|id| self.cx.tcx.fn_sig(id).skip_binder().safety() == Safety::Unsafe) => { ControlFlow::Break(()) }, @@ -444,7 +442,7 @@ pub fn is_expr_unsafe<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> bool { .cx .qpath_res(p, e.hir_id) .opt_def_id() - .map_or(false, |id| self.cx.tcx.is_mutable_static(id)) => + .is_some_and(|id| self.cx.tcx.is_mutable_static(id)) => { ControlFlow::Break(()) }, diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain index 37d9cce2465..e32e0cb3604 100644 --- a/src/tools/clippy/rust-toolchain +++ b/src/tools/clippy/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2024-11-07" +channel = "nightly-2024-11-14" components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] profile = "minimal" diff --git a/src/tools/clippy/tests/ui-internal/unnecessary_def_path.fixed b/src/tools/clippy/tests/ui-internal/unnecessary_def_path.fixed index 0a994842834..d3fab60f9e3 100644 --- a/src/tools/clippy/tests/ui-internal/unnecessary_def_path.fixed +++ b/src/tools/clippy/tests/ui-internal/unnecessary_def_path.fixed @@ -1,6 +1,7 @@ //@aux-build:paths.rs #![deny(clippy::internal)] #![feature(rustc_private)] +#![allow(clippy::unnecessary_map_or)] extern crate clippy_utils; extern crate paths; diff --git a/src/tools/clippy/tests/ui-internal/unnecessary_def_path.rs b/src/tools/clippy/tests/ui-internal/unnecessary_def_path.rs index ba68de6c6d0..1b36f6b09e9 100644 --- a/src/tools/clippy/tests/ui-internal/unnecessary_def_path.rs +++ b/src/tools/clippy/tests/ui-internal/unnecessary_def_path.rs @@ -1,6 +1,7 @@ //@aux-build:paths.rs #![deny(clippy::internal)] #![feature(rustc_private)] +#![allow(clippy::unnecessary_map_or)] extern crate clippy_utils; extern crate paths; diff --git a/src/tools/clippy/tests/ui-internal/unnecessary_def_path.stderr b/src/tools/clippy/tests/ui-internal/unnecessary_def_path.stderr index 79da1731613..79521c5037a 100644 --- a/src/tools/clippy/tests/ui-internal/unnecessary_def_path.stderr +++ b/src/tools/clippy/tests/ui-internal/unnecessary_def_path.stderr @@ -1,5 +1,5 @@ error: use of a def path to a diagnostic item - --> tests/ui-internal/unnecessary_def_path.rs:36:13 + --> tests/ui-internal/unnecessary_def_path.rs:37:13 | LL | let _ = match_type(cx, ty, &OPTION); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::Option)` @@ -12,61 +12,61 @@ LL | #![deny(clippy::internal)] = note: `#[deny(clippy::unnecessary_def_path)]` implied by `#[deny(clippy::internal)]` error: use of a def path to a diagnostic item - --> tests/ui-internal/unnecessary_def_path.rs:37:13 + --> tests/ui-internal/unnecessary_def_path.rs:38:13 | LL | let _ = match_type(cx, ty, RESULT); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::Result)` error: use of a def path to a diagnostic item - --> tests/ui-internal/unnecessary_def_path.rs:38:13 + --> tests/ui-internal/unnecessary_def_path.rs:39:13 | LL | let _ = match_type(cx, ty, &["core", "result", "Result"]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::Result)` error: use of a def path to a diagnostic item - --> tests/ui-internal/unnecessary_def_path.rs:42:13 + --> tests/ui-internal/unnecessary_def_path.rs:43:13 | LL | let _ = clippy_utils::ty::match_type(cx, ty, rc_path); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::Rc)` error: use of a def path to a diagnostic item - --> tests/ui-internal/unnecessary_def_path.rs:44:13 + --> tests/ui-internal/unnecessary_def_path.rs:45:13 | LL | let _ = match_type(cx, ty, &paths::OPTION); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::Option)` error: use of a def path to a diagnostic item - --> tests/ui-internal/unnecessary_def_path.rs:45:13 + --> tests/ui-internal/unnecessary_def_path.rs:46:13 | LL | let _ = match_type(cx, ty, paths::RESULT); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::Result)` error: use of a def path to a `LangItem` - --> tests/ui-internal/unnecessary_def_path.rs:47:13 + --> tests/ui-internal/unnecessary_def_path.rs:48:13 | LL | let _ = match_type(cx, ty, &["alloc", "boxed", "Box"]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_lang_item(cx, ty, LangItem::OwnedBox)` error: use of a def path to a diagnostic item - --> tests/ui-internal/unnecessary_def_path.rs:48:13 + --> tests/ui-internal/unnecessary_def_path.rs:49:13 | LL | let _ = match_type(cx, ty, &["core", "mem", "maybe_uninit", "MaybeUninit", "uninit"]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::maybe_uninit_uninit)` error: use of a def path to a `LangItem` - --> tests/ui-internal/unnecessary_def_path.rs:50:13 + --> tests/ui-internal/unnecessary_def_path.rs:51:13 | LL | let _ = match_def_path(cx, did, &["alloc", "boxed", "Box"]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cx.tcx.lang_items().get(LangItem::OwnedBox) == Some(did)` error: use of a def path to a diagnostic item - --> tests/ui-internal/unnecessary_def_path.rs:51:13 + --> tests/ui-internal/unnecessary_def_path.rs:52:13 | LL | let _ = match_def_path(cx, did, &["core", "option", "Option"]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cx.tcx.is_diagnostic_item(sym::Option, did)` error: use of a def path to a `LangItem` - --> tests/ui-internal/unnecessary_def_path.rs:52:13 + --> tests/ui-internal/unnecessary_def_path.rs:53:13 | LL | let _ = match_def_path(cx, did, &["core", "option", "Option", "Some"]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cx.tcx.lang_items().get(LangItem::OptionSome) == Some(did)` @@ -74,25 +74,25 @@ LL | let _ = match_def_path(cx, did, &["core", "option", "Option", "Some"]); = help: if this `DefId` came from a constructor expression or pattern then the parent `DefId` should be used instead error: use of a def path to a diagnostic item - --> tests/ui-internal/unnecessary_def_path.rs:54:13 + --> tests/ui-internal/unnecessary_def_path.rs:55:13 | LL | let _ = match_trait_method(cx, expr, &["core", "convert", "AsRef"]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_trait_method(cx, expr, sym::AsRef)` error: use of a def path to a diagnostic item - --> tests/ui-internal/unnecessary_def_path.rs:56:13 + --> tests/ui-internal/unnecessary_def_path.rs:57:13 | LL | let _ = is_expr_path_def_path(cx, expr, &["core", "option", "Option"]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_path_diagnostic_item(cx, expr, sym::Option)` error: use of a def path to a `LangItem` - --> tests/ui-internal/unnecessary_def_path.rs:57:13 + --> tests/ui-internal/unnecessary_def_path.rs:58:13 | LL | let _ = is_expr_path_def_path(cx, expr, &["core", "iter", "traits", "Iterator", "next"]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `path_res(cx, expr).opt_def_id().map_or(false, |id| cx.tcx.lang_items().get(LangItem::IteratorNext) == Some(id))` error: use of a def path to a `LangItem` - --> tests/ui-internal/unnecessary_def_path.rs:58:13 + --> tests/ui-internal/unnecessary_def_path.rs:59:13 | LL | let _ = is_expr_path_def_path(cx, expr, &["core", "option", "Option", "Some"]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_res_lang_ctor(cx, path_res(cx, expr), LangItem::OptionSome)` diff --git a/src/tools/clippy/tests/ui-toml/large_include_file/empty.txt b/src/tools/clippy/tests/ui-toml/large_include_file/empty.txt new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/large_include_file/empty.txt diff --git a/src/tools/clippy/tests/ui-toml/large_include_file/large_include_file.rs b/src/tools/clippy/tests/ui-toml/large_include_file/large_include_file.rs index dc9349f75a0..8a6dd36501c 100644 --- a/src/tools/clippy/tests/ui-toml/large_include_file/large_include_file.rs +++ b/src/tools/clippy/tests/ui-toml/large_include_file/large_include_file.rs @@ -15,5 +15,9 @@ const TOO_BIG_INCLUDE_BYTES: &[u8; 654] = include_bytes!("too_big.txt"); const TOO_BIG_INCLUDE_STR: &str = include_str!("too_big.txt"); //~^ large_include_file -#[doc = include_str!("too_big.txt")] //~ large_include_file +#[doc = include_str!("too_big.txt")] +//~^ large_include_file +// Should not lint! +// Regression test for <https://github.com/rust-lang/rust-clippy/issues/13670>. +#[doc = include_str!("empty.txt")] fn main() {} diff --git a/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.fixed b/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.fixed index 8b4a165a97c..c4d77f24f12 100644 --- a/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.fixed +++ b/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.fixed @@ -1,4 +1,5 @@ #![warn(clippy::case_sensitive_file_extension_comparisons)] +#![allow(clippy::unnecessary_map_or)] use std::string::String; diff --git a/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.rs b/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.rs index e4b8178110b..690e93c2639 100644 --- a/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.rs +++ b/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.rs @@ -1,4 +1,5 @@ #![warn(clippy::case_sensitive_file_extension_comparisons)] +#![allow(clippy::unnecessary_map_or)] use std::string::String; diff --git a/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.stderr b/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.stderr index d203f91b832..e21815f251b 100644 --- a/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.stderr +++ b/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.stderr @@ -1,5 +1,5 @@ error: case-sensitive file extension comparison - --> tests/ui/case_sensitive_file_extension_comparisons.rs:13:5 + --> tests/ui/case_sensitive_file_extension_comparisons.rs:14:5 | LL | filename.ends_with(".rs") | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -15,7 +15,7 @@ LL + .map_or(false, |ext| ext.eq_ignore_ascii_case("rs")) | error: case-sensitive file extension comparison - --> tests/ui/case_sensitive_file_extension_comparisons.rs:18:13 + --> tests/ui/case_sensitive_file_extension_comparisons.rs:19:13 | LL | let _ = String::new().ends_with(".ext12"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -29,7 +29,7 @@ LL ~ .map_or(false, |ext| ext.eq_ignore_ascii_case("ext12")); | error: case-sensitive file extension comparison - --> tests/ui/case_sensitive_file_extension_comparisons.rs:19:13 + --> tests/ui/case_sensitive_file_extension_comparisons.rs:20:13 | LL | let _ = "str".ends_with(".ext12"); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -43,7 +43,7 @@ LL ~ .map_or(false, |ext| ext.eq_ignore_ascii_case("ext12")); | error: case-sensitive file extension comparison - --> tests/ui/case_sensitive_file_extension_comparisons.rs:23:17 + --> tests/ui/case_sensitive_file_extension_comparisons.rs:24:17 | LL | let _ = "str".ends_with(".ext12"); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -57,7 +57,7 @@ LL ~ .map_or(false, |ext| ext.eq_ignore_ascii_case("ext12")); | error: case-sensitive file extension comparison - --> tests/ui/case_sensitive_file_extension_comparisons.rs:30:13 + --> tests/ui/case_sensitive_file_extension_comparisons.rs:31:13 | LL | let _ = String::new().ends_with(".EXT12"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -71,7 +71,7 @@ LL ~ .map_or(false, |ext| ext.eq_ignore_ascii_case("EXT12")); | error: case-sensitive file extension comparison - --> tests/ui/case_sensitive_file_extension_comparisons.rs:31:13 + --> tests/ui/case_sensitive_file_extension_comparisons.rs:32:13 | LL | let _ = "str".ends_with(".EXT12"); | ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/empty_line_after/doc_comments.stderr b/src/tools/clippy/tests/ui/empty_line_after/doc_comments.stderr index c238b4c9a17..2852e26680f 100644 --- a/src/tools/clippy/tests/ui/empty_line_after/doc_comments.stderr +++ b/src/tools/clippy/tests/ui/empty_line_after/doc_comments.stderr @@ -3,7 +3,7 @@ error: empty line after doc comment | LL | / /// for the crate LL | | - | |_ + | |_^ LL | fn first_in_crate() {} | ------------------- the comment documents this function | @@ -22,7 +22,7 @@ error: empty line after doc comment | LL | / /// for the module LL | | - | |_ + | |_^ LL | fn first_in_module() {} | -------------------- the comment documents this function | @@ -39,7 +39,7 @@ error: empty line after doc comment | LL | / /// # Indented LL | | - | |_ + | |_^ LL | /// Blank line LL | fn indented() {} | ------------- the comment documents this function @@ -55,7 +55,7 @@ error: empty line after doc comment | LL | / /// This should produce a warning LL | | - | |_ + | |_^ LL | fn with_doc_and_newline() {} | ------------------------- the comment documents this function | @@ -69,7 +69,7 @@ LL | | LL | | /** This is also a doc comment and is part of the warning LL | | */ LL | | - | |_ + | |_^ ... LL | fn three_attributes() {} | --------------------- the comment documents this function @@ -82,7 +82,7 @@ error: empty line after doc comment LL | / /// docs for `old_code` LL | | // fn old_code() {} LL | | - | |_ + | |_^ LL | fn new_code() {} | ------------- the comment documents this function | @@ -102,7 +102,7 @@ LL | | /// Docs LL | | /// for OldB LL | | // struct OldB; LL | | - | |_ + | |_^ ... LL | struct Multiple; | --------------- the comment documents this struct @@ -125,7 +125,7 @@ LL | / /** LL | | * Meant to be inner doc comment LL | | */ LL | | - | |_ + | |_^ LL | fn first_in_module() {} | -------------------- the comment documents this function | @@ -143,7 +143,7 @@ LL | | * Docs for `old_code` LL | | */ LL | | /* fn old_code() {} */ LL | | - | |_ + | |_^ ... LL | fn new_code() {} | ------------- the comment documents this function @@ -161,7 +161,7 @@ error: empty line after doc comment LL | / /// Docs for `old_code2` LL | | /* fn old_code2() {} */ LL | | - | |_ + | |_^ LL | /// Docs for `new_code2` LL | fn new_code2() {} | -------------- the comment documents this function diff --git a/src/tools/clippy/tests/ui/empty_line_after/outer_attribute.stderr b/src/tools/clippy/tests/ui/empty_line_after/outer_attribute.stderr index 958b40424a9..75fc23e9e7e 100644 --- a/src/tools/clippy/tests/ui/empty_line_after/outer_attribute.stderr +++ b/src/tools/clippy/tests/ui/empty_line_after/outer_attribute.stderr @@ -3,7 +3,7 @@ error: empty line after outer attribute | LL | / #[crate_type = "lib"] LL | | - | |_ + | |_^ LL | fn first_in_crate() {} | ------------------- the attribute applies to this function | @@ -20,7 +20,7 @@ error: empty line after outer attribute | LL | / #[inline] LL | | - | |_ + | |_^ LL | /// some comment LL | fn with_one_newline_and_comment() {} | --------------------------------- the attribute applies to this function @@ -32,7 +32,7 @@ error: empty line after outer attribute | LL | / #[inline] LL | | - | |_ + | |_^ LL | fn with_one_newline() {} | --------------------- the attribute applies to this function | @@ -44,7 +44,7 @@ error: empty lines after outer attribute LL | / #[crate_type = "lib"] LL | | LL | | - | |_ + | |_^ LL | fn with_two_newlines() {} | ---------------------- the attribute applies to this function | @@ -59,7 +59,7 @@ error: empty line after outer attribute | LL | / #[doc = "doc attributes should be considered attributes"] LL | | - | |_ + | |_^ LL | enum Baz { | -------- the attribute applies to this enum | @@ -70,7 +70,7 @@ error: empty line after outer attribute | LL | / #[repr(C)] LL | | - | |_ + | |_^ LL | struct Foo { | ---------- the attribute applies to this struct | @@ -81,7 +81,7 @@ error: empty line after outer attribute | LL | / #[allow(dead_code)] LL | | - | |_ + | |_^ LL | mod foo {} | ------- the attribute applies to this module | @@ -93,7 +93,7 @@ error: empty line after outer attribute LL | / #[inline] LL | | // Still lint cases where the empty line does not immediately follow the attribute LL | | - | |_ + | |_^ LL | fn comment_before_empty_line() {} | ------------------------------ the attribute applies to this function | @@ -106,7 +106,7 @@ LL | / #[allow(unused)] LL | | LL | | // This comment is isolated LL | | - | |_ + | |_^ LL | pub fn isolated_comment() {} | ------------------------- the attribute applies to this function | diff --git a/src/tools/clippy/tests/ui/four_forward_slashes.stderr b/src/tools/clippy/tests/ui/four_forward_slashes.stderr index a2218ea4d10..3606a2227a0 100644 --- a/src/tools/clippy/tests/ui/four_forward_slashes.stderr +++ b/src/tools/clippy/tests/ui/four_forward_slashes.stderr @@ -3,7 +3,7 @@ error: this item has comments with 4 forward slashes (`////`). These look like d | LL | / //// whoops LL | | fn a() {} - | |_ + | |_^ | = note: `-D clippy::four-forward-slashes` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::four_forward_slashes)]` @@ -18,7 +18,7 @@ error: this item has comments with 4 forward slashes (`////`). These look like d LL | / //// whoops LL | | #[allow(dead_code)] LL | | fn b() {} - | |_ + | |_^ | help: make this a doc comment by removing one `/` | @@ -32,7 +32,7 @@ LL | / //// whoops LL | | //// two borked comments! LL | | #[track_caller] LL | | fn c() {} - | |_ + | |_^ | help: turn these into doc comments by removing one `/` | @@ -46,7 +46,7 @@ error: this item has comments with 4 forward slashes (`////`). These look like d LL | / //// between attributes LL | | #[allow(dead_code)] LL | | fn g() {} - | |_ + | |_^ | help: make this a doc comment by removing one `/` | @@ -58,7 +58,7 @@ error: this item has comments with 4 forward slashes (`////`). These look like d | LL | / //// not very start of contents LL | | fn h() {} - | |_ + | |_^ | help: make this a doc comment by removing one `/` | diff --git a/src/tools/clippy/tests/ui/four_forward_slashes_first_line.stderr b/src/tools/clippy/tests/ui/four_forward_slashes_first_line.stderr index 23937034b7e..81732346412 100644 --- a/src/tools/clippy/tests/ui/four_forward_slashes_first_line.stderr +++ b/src/tools/clippy/tests/ui/four_forward_slashes_first_line.stderr @@ -3,7 +3,7 @@ error: this item has comments with 4 forward slashes (`////`). These look like d | LL | / //// borked doc comment on the first line. doesn't combust! LL | | fn a() {} - | |_ + | |_^ | = note: `-D clippy::four-forward-slashes` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::four_forward_slashes)]` diff --git a/src/tools/clippy/tests/ui/identity_op.fixed b/src/tools/clippy/tests/ui/identity_op.fixed index b18d8560f6f..2e8e2366de6 100644 --- a/src/tools/clippy/tests/ui/identity_op.fixed +++ b/src/tools/clippy/tests/ui/identity_op.fixed @@ -116,7 +116,7 @@ fn main() { //~^ ERROR: this operation has no effect (match a { 0 => 10, _ => 20 }) + if b { 3 } else { 4 }; //~^ ERROR: this operation has no effect - (if b { 1 } else { 2 }); + ((if b { 1 } else { 2 })); //~^ ERROR: this operation has no effect ({ a }) + 3; @@ -212,3 +212,47 @@ fn issue_12050() { //~^ ERROR: this operation has no effect } } + +fn issue_13470() { + let x = 1i32; + let y = 1i32; + // Removes the + 0i32 while keeping the parentheses around x + y so the cast operation works + let _: u64 = (x + y) as u64; + //~^ ERROR: this operation has no effect + // both of the next two lines should look the same after rustfix + let _: u64 = 1u64 & (x + y) as u64; + //~^ ERROR: this operation has no effect + // Same as above, but with extra redundant parenthesis + let _: u64 = 1u64 & ((x + y)) as u64; + //~^ ERROR: this operation has no effect + // Should maintain parenthesis even if the surrounding expr has the same precedence + let _: u64 = 5u64 + ((x + y)) as u64; + //~^ ERROR: this operation has no effect + + // If we don't maintain the parens here, the behavior changes + let _ = -(x + y); + //~^ ERROR: this operation has no effect + // Similarly, we need to maintain parens here + let _ = -(x / y); + //~^ ERROR: this operation has no effect + // Maintain parenthesis if the parent expr is of higher precedence + let _ = 2i32 * (x + y); + //~^ ERROR: this operation has no effect + // Maintain parenthesis if the parent expr is the same precedence + // as not all operations are associative + let _ = 2i32 - (x - y); + //~^ ERROR: this operation has no effect + // But make sure that inner parens still exist + let z = 1i32; + let _ = 2 + (x + (y * z)); + //~^ ERROR: this operation has no effect + // Maintain parenthesis if the parent expr is of lower precedence + // This is for clarity, and clippy will not warn on these being unnecessary + let _ = 2i32 + (x * y); + //~^ ERROR: this operation has no effect + + let x = 1i16; + let y = 1i16; + let _: u64 = 1u64 + ((x as i32 + y as i32) as u64); + //~^ ERROR: this operation has no effect +} diff --git a/src/tools/clippy/tests/ui/identity_op.rs b/src/tools/clippy/tests/ui/identity_op.rs index f1f01b42447..3e20fa6f2b8 100644 --- a/src/tools/clippy/tests/ui/identity_op.rs +++ b/src/tools/clippy/tests/ui/identity_op.rs @@ -212,3 +212,47 @@ fn issue_12050() { //~^ ERROR: this operation has no effect } } + +fn issue_13470() { + let x = 1i32; + let y = 1i32; + // Removes the + 0i32 while keeping the parentheses around x + y so the cast operation works + let _: u64 = (x + y + 0i32) as u64; + //~^ ERROR: this operation has no effect + // both of the next two lines should look the same after rustfix + let _: u64 = 1u64 & (x + y + 0i32) as u64; + //~^ ERROR: this operation has no effect + // Same as above, but with extra redundant parenthesis + let _: u64 = 1u64 & ((x + y) + 0i32) as u64; + //~^ ERROR: this operation has no effect + // Should maintain parenthesis even if the surrounding expr has the same precedence + let _: u64 = 5u64 + ((x + y) + 0i32) as u64; + //~^ ERROR: this operation has no effect + + // If we don't maintain the parens here, the behavior changes + let _ = -(x + y + 0i32); + //~^ ERROR: this operation has no effect + // Similarly, we need to maintain parens here + let _ = -(x / y / 1i32); + //~^ ERROR: this operation has no effect + // Maintain parenthesis if the parent expr is of higher precedence + let _ = 2i32 * (x + y + 0i32); + //~^ ERROR: this operation has no effect + // Maintain parenthesis if the parent expr is the same precedence + // as not all operations are associative + let _ = 2i32 - (x - y - 0i32); + //~^ ERROR: this operation has no effect + // But make sure that inner parens still exist + let z = 1i32; + let _ = 2 + (x + (y * z) + 0); + //~^ ERROR: this operation has no effect + // Maintain parenthesis if the parent expr is of lower precedence + // This is for clarity, and clippy will not warn on these being unnecessary + let _ = 2i32 + (x * y * 1i32); + //~^ ERROR: this operation has no effect + + let x = 1i16; + let y = 1i16; + let _: u64 = 1u64 + ((x as i32 + y as i32) as u64 + 0u64); + //~^ ERROR: this operation has no effect +} diff --git a/src/tools/clippy/tests/ui/identity_op.stderr b/src/tools/clippy/tests/ui/identity_op.stderr index 9fff86b86f9..99a58ef2c1b 100644 --- a/src/tools/clippy/tests/ui/identity_op.stderr +++ b/src/tools/clippy/tests/ui/identity_op.stderr @@ -149,7 +149,7 @@ error: this operation has no effect --> tests/ui/identity_op.rs:119:5 | LL | (if b { 1 } else { 2 }) + 0; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `(if b { 1 } else { 2 })` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `((if b { 1 } else { 2 }))` error: this operation has no effect --> tests/ui/identity_op.rs:122:5 @@ -313,5 +313,71 @@ error: this operation has no effect LL | let _: i32 = **&&*&x + 0; | ^^^^^^^^^^^ help: consider reducing it to: `***&&*&x` -error: aborting due to 52 previous errors +error: this operation has no effect + --> tests/ui/identity_op.rs:220:18 + | +LL | let _: u64 = (x + y + 0i32) as u64; + | ^^^^^^^^^^^^^^ help: consider reducing it to: `(x + y)` + +error: this operation has no effect + --> tests/ui/identity_op.rs:223:25 + | +LL | let _: u64 = 1u64 & (x + y + 0i32) as u64; + | ^^^^^^^^^^^^^^ help: consider reducing it to: `(x + y)` + +error: this operation has no effect + --> tests/ui/identity_op.rs:226:25 + | +LL | let _: u64 = 1u64 & ((x + y) + 0i32) as u64; + | ^^^^^^^^^^^^^^^^ help: consider reducing it to: `((x + y))` + +error: this operation has no effect + --> tests/ui/identity_op.rs:229:25 + | +LL | let _: u64 = 5u64 + ((x + y) + 0i32) as u64; + | ^^^^^^^^^^^^^^^^ help: consider reducing it to: `((x + y))` + +error: this operation has no effect + --> tests/ui/identity_op.rs:233:14 + | +LL | let _ = -(x + y + 0i32); + | ^^^^^^^^^^^^^^ help: consider reducing it to: `(x + y)` + +error: this operation has no effect + --> tests/ui/identity_op.rs:236:14 + | +LL | let _ = -(x / y / 1i32); + | ^^^^^^^^^^^^^^ help: consider reducing it to: `(x / y)` + +error: this operation has no effect + --> tests/ui/identity_op.rs:239:20 + | +LL | let _ = 2i32 * (x + y + 0i32); + | ^^^^^^^^^^^^^^ help: consider reducing it to: `(x + y)` + +error: this operation has no effect + --> tests/ui/identity_op.rs:243:20 + | +LL | let _ = 2i32 - (x - y - 0i32); + | ^^^^^^^^^^^^^^ help: consider reducing it to: `(x - y)` + +error: this operation has no effect + --> tests/ui/identity_op.rs:247:17 + | +LL | let _ = 2 + (x + (y * z) + 0); + | ^^^^^^^^^^^^^^^^^ help: consider reducing it to: `(x + (y * z))` + +error: this operation has no effect + --> tests/ui/identity_op.rs:251:20 + | +LL | let _ = 2i32 + (x * y * 1i32); + | ^^^^^^^^^^^^^^ help: consider reducing it to: `(x * y)` + +error: this operation has no effect + --> tests/ui/identity_op.rs:256:25 + | +LL | let _: u64 = 1u64 + ((x as i32 + y as i32) as u64 + 0u64); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `((x as i32 + y as i32) as u64)` + +error: aborting due to 63 previous errors diff --git a/src/tools/clippy/tests/ui/question_mark.fixed b/src/tools/clippy/tests/ui/question_mark.fixed index 679388372e6..b6e148e9f77 100644 --- a/src/tools/clippy/tests/ui/question_mark.fixed +++ b/src/tools/clippy/tests/ui/question_mark.fixed @@ -96,12 +96,42 @@ impl MoveStruct { } fn func() -> Option<i32> { + macro_rules! opt_none { + () => { + None + }; + } + fn f() -> Option<String> { Some(String::new()) } f()?; + let _val = f()?; + + let s: &str = match &Some(String::new()) { + Some(v) => v, + None => return None, + }; + + f()?; + + opt_none!()?; + + match f() { + Some(x) => x, + None => return opt_none!(), + }; + + match f() { + Some(val) => { + println!("{val}"); + val + }, + None => return None, + }; + Some(0) } @@ -114,6 +144,10 @@ fn result_func(x: Result<i32, i32>) -> Result<i32, i32> { x?; + let _val = func_returning_result()?; + + func_returning_result()?; + // No warning let y = if let Ok(x) = x { x @@ -157,6 +191,28 @@ fn result_func(x: Result<i32, i32>) -> Result<i32, i32> { Ok(y) } +fn infer_check() { + let closure = |x: Result<u8, ()>| { + // `?` would fail here, as it expands to `Err(val.into())` which is not constrained. + let _val = match x { + Ok(val) => val, + Err(val) => return Err(val), + }; + + Ok(()) + }; + + let closure = |x: Result<u8, ()>| -> Result<(), _> { + // `?` would fail here, as it expands to `Err(val.into())` which is not constrained. + let _val = match x { + Ok(val) => val, + Err(val) => return Err(val), + }; + + Ok(()) + }; +} + // see issue #8019 pub enum NotOption { None, diff --git a/src/tools/clippy/tests/ui/question_mark.rs b/src/tools/clippy/tests/ui/question_mark.rs index 601ab78bf5a..48dc9eb0a62 100644 --- a/src/tools/clippy/tests/ui/question_mark.rs +++ b/src/tools/clippy/tests/ui/question_mark.rs @@ -124,6 +124,12 @@ impl MoveStruct { } fn func() -> Option<i32> { + macro_rules! opt_none { + () => { + None + }; + } + fn f() -> Option<String> { Some(String::new()) } @@ -132,6 +138,39 @@ fn func() -> Option<i32> { return None; } + let _val = match f() { + Some(val) => val, + None => return None, + }; + + let s: &str = match &Some(String::new()) { + Some(v) => v, + None => return None, + }; + + match f() { + Some(val) => val, + None => return None, + }; + + match opt_none!() { + Some(x) => x, + None => return None, + }; + + match f() { + Some(x) => x, + None => return opt_none!(), + }; + + match f() { + Some(val) => { + println!("{val}"); + val + }, + None => return None, + }; + Some(0) } @@ -146,6 +185,16 @@ fn result_func(x: Result<i32, i32>) -> Result<i32, i32> { return x; } + let _val = match func_returning_result() { + Ok(val) => val, + Err(err) => return Err(err), + }; + + match func_returning_result() { + Ok(val) => val, + Err(err) => return Err(err), + }; + // No warning let y = if let Ok(x) = x { x @@ -189,6 +238,28 @@ fn result_func(x: Result<i32, i32>) -> Result<i32, i32> { Ok(y) } +fn infer_check() { + let closure = |x: Result<u8, ()>| { + // `?` would fail here, as it expands to `Err(val.into())` which is not constrained. + let _val = match x { + Ok(val) => val, + Err(val) => return Err(val), + }; + + Ok(()) + }; + + let closure = |x: Result<u8, ()>| -> Result<(), _> { + // `?` would fail here, as it expands to `Err(val.into())` which is not constrained. + let _val = match x { + Ok(val) => val, + Err(val) => return Err(val), + }; + + Ok(()) + }; +} + // see issue #8019 pub enum NotOption { None, diff --git a/src/tools/clippy/tests/ui/question_mark.stderr b/src/tools/clippy/tests/ui/question_mark.stderr index 5f26a7ea2c3..0a48c4e80cb 100644 --- a/src/tools/clippy/tests/ui/question_mark.stderr +++ b/src/tools/clippy/tests/ui/question_mark.stderr @@ -94,29 +94,76 @@ LL | | }; | |_________^ help: replace it with: `self.opt?` error: this block may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:131:5 + --> tests/ui/question_mark.rs:137:5 | LL | / if f().is_none() { LL | | return None; LL | | } | |_____^ help: replace it with: `f()?;` +error: this `match` expression can be replaced with `?` + --> tests/ui/question_mark.rs:141:16 + | +LL | let _val = match f() { + | ________________^ +LL | | Some(val) => val, +LL | | None => return None, +LL | | }; + | |_____^ help: try instead: `f()?` + +error: this `match` expression can be replaced with `?` + --> tests/ui/question_mark.rs:151:5 + | +LL | / match f() { +LL | | Some(val) => val, +LL | | None => return None, +LL | | }; + | |_____^ help: try instead: `f()?` + +error: this `match` expression can be replaced with `?` + --> tests/ui/question_mark.rs:156:5 + | +LL | / match opt_none!() { +LL | | Some(x) => x, +LL | | None => return None, +LL | | }; + | |_____^ help: try instead: `opt_none!()?` + error: this block may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:143:13 + --> tests/ui/question_mark.rs:182:13 | LL | let _ = if let Ok(x) = x { x } else { return x }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `x?` error: this block may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:145:5 + --> tests/ui/question_mark.rs:184:5 | LL | / if x.is_err() { LL | | return x; LL | | } | |_____^ help: replace it with: `x?;` +error: this `match` expression can be replaced with `?` + --> tests/ui/question_mark.rs:188:16 + | +LL | let _val = match func_returning_result() { + | ________________^ +LL | | Ok(val) => val, +LL | | Err(err) => return Err(err), +LL | | }; + | |_____^ help: try instead: `func_returning_result()?` + +error: this `match` expression can be replaced with `?` + --> tests/ui/question_mark.rs:193:5 + | +LL | / match func_returning_result() { +LL | | Ok(val) => val, +LL | | Err(err) => return Err(err), +LL | | }; + | |_____^ help: try instead: `func_returning_result()?` + error: this block may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:213:5 + --> tests/ui/question_mark.rs:284:5 | LL | / if let Err(err) = func_returning_result() { LL | | return Err(err); @@ -124,7 +171,7 @@ LL | | } | |_____^ help: replace it with: `func_returning_result()?;` error: this block may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:220:5 + --> tests/ui/question_mark.rs:291:5 | LL | / if let Err(err) = func_returning_result() { LL | | return Err(err); @@ -132,7 +179,7 @@ LL | | } | |_____^ help: replace it with: `func_returning_result()?;` error: this block may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:297:13 + --> tests/ui/question_mark.rs:368:13 | LL | / if a.is_none() { LL | | return None; @@ -142,12 +189,12 @@ LL | | } | |_____________^ help: replace it with: `a?;` error: this `let...else` may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:357:5 + --> tests/ui/question_mark.rs:428:5 | LL | / let Some(v) = bar.foo.owned.clone() else { LL | | return None; LL | | }; | |______^ help: replace it with: `let v = bar.foo.owned.clone()?;` -error: aborting due to 17 previous errors +error: aborting due to 22 previous errors diff --git a/src/tools/clippy/tests/ui/too_long_first_doc_paragraph-fix.stderr b/src/tools/clippy/tests/ui/too_long_first_doc_paragraph-fix.stderr index 6403265a39c..6ef333f0cfd 100644 --- a/src/tools/clippy/tests/ui/too_long_first_doc_paragraph-fix.stderr +++ b/src/tools/clippy/tests/ui/too_long_first_doc_paragraph-fix.stderr @@ -6,7 +6,7 @@ LL | | /// A much longer explanation that goes into a lot more detail about LL | | /// how the thing works, possibly with doclinks and so one, LL | | /// and probably spanning a many rows. Blablabla, it needs to be over LL | | /// 200 characters so I needed to write something longeeeeeeer. - | |_ + | |_^ | = note: `-D clippy::too-long-first-doc-paragraph` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::too_long_first_doc_paragraph)]` diff --git a/src/tools/clippy/tests/ui/too_long_first_doc_paragraph.stderr b/src/tools/clippy/tests/ui/too_long_first_doc_paragraph.stderr index 39926647f54..95f42349b9b 100644 --- a/src/tools/clippy/tests/ui/too_long_first_doc_paragraph.stderr +++ b/src/tools/clippy/tests/ui/too_long_first_doc_paragraph.stderr @@ -23,7 +23,7 @@ error: first doc comment paragraph is too long LL | / /// Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc turpis nunc, lacinia LL | | /// a dolor in, pellentesque aliquet enim. Cras nec maximus sem. Mauris arcu libero, LL | | /// gravida non lacinia at, rhoncus eu lacus. - | |_ + | |_^ error: first doc comment paragraph is too long --> tests/ui/too_long_first_doc_paragraph.rs:36:1 @@ -32,7 +32,7 @@ LL | / /// Lorem LL | | /// ipsum dolor sit amet, consectetur adipiscing elit. Nunc turpis nunc, lacinia LL | | /// a dolor in, pellentesque aliquet enim. Cras nec maximus sem. Mauris arcu libero, LL | | /// gravida non lacinia at, rhoncus eu lacus. - | |_ + | |_^ error: aborting due to 3 previous errors diff --git a/src/tools/clippy/tests/ui/unnecessary_map_or.fixed b/src/tools/clippy/tests/ui/unnecessary_map_or.fixed new file mode 100644 index 00000000000..2d932a70e9d --- /dev/null +++ b/src/tools/clippy/tests/ui/unnecessary_map_or.fixed @@ -0,0 +1,64 @@ +//@aux-build:proc_macros.rs +#![warn(clippy::unnecessary_map_or)] +#![allow(clippy::no_effect)] +#![allow(clippy::eq_op)] +#![allow(clippy::unnecessary_lazy_evaluations)] +#[clippy::msrv = "1.70.0"] +#[macro_use] +extern crate proc_macros; + +fn main() { + // should trigger + let _ = (Some(5) == Some(5)); + let _ = (Some(5) != Some(5)); + let _ = (Some(5) == Some(5)); + let _ = Some(5).is_some_and(|n| { + let _ = n; + 6 >= 5 + }); + let _ = Some(vec![5]).is_some_and(|n| n == [5]); + let _ = Some(vec![1]).is_some_and(|n| vec![2] == n); + let _ = Some(5).is_some_and(|n| n == n); + let _ = Some(5).is_some_and(|n| n == if 2 > 1 { n } else { 0 }); + let _ = Ok::<Vec<i32>, i32>(vec![5]).is_ok_and(|n| n == [5]); + let _ = (Ok::<i32, i32>(5) == Ok(5)); + let _ = (Some(5) == Some(5)).then(|| 1); + + // shouldnt trigger + let _ = Some(5).map_or(true, |n| n == 5); + let _ = Some(5).map_or(true, |n| 5 == n); + macro_rules! x { + () => { + Some(1) + }; + } + // methods lints dont fire on macros + let _ = x!().map_or(false, |n| n == 1); + let _ = x!().map_or(false, |n| n == vec![1][0]); + + msrv_1_69(); + + external! { + let _ = Some(5).map_or(false, |n| n == 5); + } + + with_span! { + let _ = Some(5).map_or(false, |n| n == 5); + } + + // check for presence of PartialEq, and alter suggestion to use `is_ok_and` if absent + struct S; + let r: Result<i32, S> = Ok(3); + let _ = r.is_ok_and(|x| x == 7); + + #[derive(PartialEq)] + struct S2; + let r: Result<i32, S2> = Ok(4); + let _ = (r == Ok(8)); +} + +#[clippy::msrv = "1.69.0"] +fn msrv_1_69() { + // is_some_and added in 1.70.0 + let _ = Some(5).map_or(false, |n| n == if 2 > 1 { n } else { 0 }); +} diff --git a/src/tools/clippy/tests/ui/unnecessary_map_or.rs b/src/tools/clippy/tests/ui/unnecessary_map_or.rs new file mode 100644 index 00000000000..4a9d69be1e9 --- /dev/null +++ b/src/tools/clippy/tests/ui/unnecessary_map_or.rs @@ -0,0 +1,67 @@ +//@aux-build:proc_macros.rs +#![warn(clippy::unnecessary_map_or)] +#![allow(clippy::no_effect)] +#![allow(clippy::eq_op)] +#![allow(clippy::unnecessary_lazy_evaluations)] +#[clippy::msrv = "1.70.0"] +#[macro_use] +extern crate proc_macros; + +fn main() { + // should trigger + let _ = Some(5).map_or(false, |n| n == 5); + let _ = Some(5).map_or(true, |n| n != 5); + let _ = Some(5).map_or(false, |n| { + let _ = 1; + n == 5 + }); + let _ = Some(5).map_or(false, |n| { + let _ = n; + 6 >= 5 + }); + let _ = Some(vec![5]).map_or(false, |n| n == [5]); + let _ = Some(vec![1]).map_or(false, |n| vec![2] == n); + let _ = Some(5).map_or(false, |n| n == n); + let _ = Some(5).map_or(false, |n| n == if 2 > 1 { n } else { 0 }); + let _ = Ok::<Vec<i32>, i32>(vec![5]).map_or(false, |n| n == [5]); + let _ = Ok::<i32, i32>(5).map_or(false, |n| n == 5); + let _ = Some(5).map_or(false, |n| n == 5).then(|| 1); + + // shouldnt trigger + let _ = Some(5).map_or(true, |n| n == 5); + let _ = Some(5).map_or(true, |n| 5 == n); + macro_rules! x { + () => { + Some(1) + }; + } + // methods lints dont fire on macros + let _ = x!().map_or(false, |n| n == 1); + let _ = x!().map_or(false, |n| n == vec![1][0]); + + msrv_1_69(); + + external! { + let _ = Some(5).map_or(false, |n| n == 5); + } + + with_span! { + let _ = Some(5).map_or(false, |n| n == 5); + } + + // check for presence of PartialEq, and alter suggestion to use `is_ok_and` if absent + struct S; + let r: Result<i32, S> = Ok(3); + let _ = r.map_or(false, |x| x == 7); + + #[derive(PartialEq)] + struct S2; + let r: Result<i32, S2> = Ok(4); + let _ = r.map_or(false, |x| x == 8); +} + +#[clippy::msrv = "1.69.0"] +fn msrv_1_69() { + // is_some_and added in 1.70.0 + let _ = Some(5).map_or(false, |n| n == if 2 > 1 { n } else { 0 }); +} diff --git a/src/tools/clippy/tests/ui/unnecessary_map_or.stderr b/src/tools/clippy/tests/ui/unnecessary_map_or.stderr new file mode 100644 index 00000000000..299a4e5da7a --- /dev/null +++ b/src/tools/clippy/tests/ui/unnecessary_map_or.stderr @@ -0,0 +1,99 @@ +error: this `map_or` is redundant + --> tests/ui/unnecessary_map_or.rs:12:13 + | +LL | let _ = Some(5).map_or(false, |n| n == 5); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `(Some(5) == Some(5))` + | + = note: `-D clippy::unnecessary-map-or` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unnecessary_map_or)]` + +error: this `map_or` is redundant + --> tests/ui/unnecessary_map_or.rs:13:13 + | +LL | let _ = Some(5).map_or(true, |n| n != 5); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `(Some(5) != Some(5))` + +error: this `map_or` is redundant + --> tests/ui/unnecessary_map_or.rs:14:13 + | +LL | let _ = Some(5).map_or(false, |n| { + | _____________^ +LL | | let _ = 1; +LL | | n == 5 +LL | | }); + | |______^ help: use a standard comparison instead: `(Some(5) == Some(5))` + +error: this `map_or` is redundant + --> tests/ui/unnecessary_map_or.rs:18:13 + | +LL | let _ = Some(5).map_or(false, |n| { + | _____________^ +LL | | let _ = n; +LL | | 6 >= 5 +LL | | }); + | |______^ + | +help: use is_some_and instead + | +LL ~ let _ = Some(5).is_some_and(|n| { +LL + let _ = n; +LL + 6 >= 5 +LL ~ }); + | + +error: this `map_or` is redundant + --> tests/ui/unnecessary_map_or.rs:22:13 + | +LL | let _ = Some(vec![5]).map_or(false, |n| n == [5]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_some_and instead: `Some(vec![5]).is_some_and(|n| n == [5])` + +error: this `map_or` is redundant + --> tests/ui/unnecessary_map_or.rs:23:13 + | +LL | let _ = Some(vec![1]).map_or(false, |n| vec![2] == n); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_some_and instead: `Some(vec![1]).is_some_and(|n| vec![2] == n)` + +error: this `map_or` is redundant + --> tests/ui/unnecessary_map_or.rs:24:13 + | +LL | let _ = Some(5).map_or(false, |n| n == n); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_some_and instead: `Some(5).is_some_and(|n| n == n)` + +error: this `map_or` is redundant + --> tests/ui/unnecessary_map_or.rs:25:13 + | +LL | let _ = Some(5).map_or(false, |n| n == if 2 > 1 { n } else { 0 }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_some_and instead: `Some(5).is_some_and(|n| n == if 2 > 1 { n } else { 0 })` + +error: this `map_or` is redundant + --> tests/ui/unnecessary_map_or.rs:26:13 + | +LL | let _ = Ok::<Vec<i32>, i32>(vec![5]).map_or(false, |n| n == [5]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_ok_and instead: `Ok::<Vec<i32>, i32>(vec![5]).is_ok_and(|n| n == [5])` + +error: this `map_or` is redundant + --> tests/ui/unnecessary_map_or.rs:27:13 + | +LL | let _ = Ok::<i32, i32>(5).map_or(false, |n| n == 5); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `(Ok::<i32, i32>(5) == Ok(5))` + +error: this `map_or` is redundant + --> tests/ui/unnecessary_map_or.rs:28:13 + | +LL | let _ = Some(5).map_or(false, |n| n == 5).then(|| 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `(Some(5) == Some(5))` + +error: this `map_or` is redundant + --> tests/ui/unnecessary_map_or.rs:55:13 + | +LL | let _ = r.map_or(false, |x| x == 7); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_ok_and instead: `r.is_ok_and(|x| x == 7)` + +error: this `map_or` is redundant + --> tests/ui/unnecessary_map_or.rs:60:13 + | +LL | let _ = r.map_or(false, |x| x == 8); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `(r == Ok(8))` + +error: aborting due to 13 previous errors + diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml index cef6b525a7b..b784bdb7139 100644 --- a/src/tools/compiletest/Cargo.toml +++ b/src/tools/compiletest/Cargo.toml @@ -14,7 +14,7 @@ unified-diff = "0.2.1" getopts = "0.2" indexmap = "2.0.0" miropt-test-tools = { path = "../miropt-test-tools" } -build_helper = { path = "../build_helper" } +build_helper = { path = "../../build_helper" } tracing = "0.1" tracing-subscriber = { version = "0.3.3", default-features = false, features = ["fmt", "env-filter", "smallvec", "parking_lot", "ansi"] } regex = "1.0" diff --git a/src/tools/compiletest/src/directive-list.rs b/src/tools/compiletest/src/directive-list.rs index 8570a8ce115..bdd0b80b395 100644 --- a/src/tools/compiletest/src/directive-list.rs +++ b/src/tools/compiletest/src/directive-list.rs @@ -25,6 +25,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "dont-check-failure-status", "edition", "error-pattern", + "exact-llvm-major-version", "exec-env", "failure-status", "filecheck-flags", @@ -35,6 +36,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "ignore-64bit", "ignore-aarch64", "ignore-aarch64-unknown-linux-gnu", + "ignore-aix", "ignore-android", "ignore-apple", "ignore-arm", @@ -118,6 +120,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "incremental", "known-bug", "llvm-cov-flags", + "max-llvm-major-version", "min-cdb-version", "min-gdb-version", "min-lldb-version", diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 300a03e5f33..3539e85ba63 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -1547,6 +1547,20 @@ fn ignore_llvm(config: &Config, line: &str) -> IgnoreDecision { }; } } else if let Some(version_string) = + config.parse_name_value_directive(line, "max-llvm-major-version") + { + let max_version = extract_llvm_version(&version_string); + // Ignore if actual major version is larger than the maximum required major version. + if actual_version.major > max_version.major { + return IgnoreDecision::Ignore { + reason: format!( + "ignored when the LLVM version ({actual_version}) is newer than major\ + version {}", + max_version.major + ), + }; + } + } else if let Some(version_string) = config.parse_name_value_directive(line, "min-system-llvm-version") { let min_version = extract_llvm_version(&version_string); @@ -1585,6 +1599,19 @@ fn ignore_llvm(config: &Config, line: &str) -> IgnoreDecision { }; } } + } else if let Some(version_string) = + config.parse_name_value_directive(line, "exact-llvm-major-version") + { + // Syntax is "exact-llvm-major-version: <version>" + let version = extract_llvm_version(&version_string); + if actual_version.major != version.major { + return IgnoreDecision::Ignore { + reason: format!( + "ignored when the actual LLVM major version is {}, but the test only targets major version {}", + actual_version.major, version.major + ), + }; + } } } IgnoreDecision::Continue diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/header/tests.rs index c3fb8d4ab80..4d75c38dd32 100644 --- a/src/tools/compiletest/src/header/tests.rs +++ b/src/tools/compiletest/src/header/tests.rs @@ -284,6 +284,30 @@ fn llvm_version() { let config: Config = cfg().llvm_version("10.0.0").build(); assert!(!check_ignore(&config, "//@ min-llvm-version: 9.0")); + + let config: Config = cfg().llvm_version("10.0.0").build(); + assert!(check_ignore(&config, "//@ exact-llvm-major-version: 9.0")); + + let config: Config = cfg().llvm_version("9.0.0").build(); + assert!(check_ignore(&config, "//@ exact-llvm-major-version: 10.0")); + + let config: Config = cfg().llvm_version("10.0.0").build(); + assert!(!check_ignore(&config, "//@ exact-llvm-major-version: 10.0")); + + let config: Config = cfg().llvm_version("10.0.0").build(); + assert!(!check_ignore(&config, "//@ exact-llvm-major-version: 10")); + + let config: Config = cfg().llvm_version("10.6.2").build(); + assert!(!check_ignore(&config, "//@ exact-llvm-major-version: 10")); + + let config: Config = cfg().llvm_version("19.0.0").build(); + assert!(!check_ignore(&config, "//@ max-llvm-major-version: 19")); + + let config: Config = cfg().llvm_version("19.1.2").build(); + assert!(!check_ignore(&config, "//@ max-llvm-major-version: 19")); + + let config: Config = cfg().llvm_version("20.0.0").build(); + assert!(check_ignore(&config, "//@ max-llvm-major-version: 19")); } #[test] diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 07d41ad7fa3..6c84893627a 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -c22887b4d97400e8e024e19fb5f724eda65ad58d +3bc6916f4ca50bb83b211d9013dac38e84618750 diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs index 63591474120..41b7be37c37 100644 --- a/src/tools/miri/src/diagnostics.rs +++ b/src/tools/miri/src/diagnostics.rs @@ -195,7 +195,7 @@ pub fn prune_stacktrace<'tcx>( // This len check ensures that we don't somehow remove every frame, as doing so breaks // the primary error message. while stacktrace.len() > 1 - && stacktrace.last().map_or(false, |frame| !machine.is_local(frame)) + && stacktrace.last().is_some_and(|frame| !machine.is_local(frame)) { stacktrace.pop(); } diff --git a/src/tools/opt-dist/Cargo.toml b/src/tools/opt-dist/Cargo.toml index d34f8ad0520..d0413911014 100644 --- a/src/tools/opt-dist/Cargo.toml +++ b/src/tools/opt-dist/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] -build_helper = { path = "../build_helper" } +build_helper = { path = "../../build_helper" } env_logger = "0.11" log = "0.4" anyhow = { version = "1", features = ["backtrace"] } diff --git a/src/tools/run-make-support/Cargo.toml b/src/tools/run-make-support/Cargo.toml index 3affa199fa5..3c172b2d956 100644 --- a/src/tools/run-make-support/Cargo.toml +++ b/src/tools/run-make-support/Cargo.toml @@ -10,7 +10,7 @@ similar = "2.5.0" wasmparser = { version = "0.216", default-features = false, features = ["std"] } regex = "1.8" # 1.8 to avoid memchr 2.6.0, as 2.5.0 is pinned in the workspace gimli = "0.31.0" -build_helper = { path = "../build_helper" } +build_helper = { path = "../../build_helper" } serde_json = "1.0" libc = "0.2" diff --git a/src/tools/run-make-support/src/external_deps/rustc.rs b/src/tools/run-make-support/src/external_deps/rustc.rs index 35d983dc607..494daeca963 100644 --- a/src/tools/run-make-support/src/external_deps/rustc.rs +++ b/src/tools/run-make-support/src/external_deps/rustc.rs @@ -5,7 +5,7 @@ use crate::command::Command; use crate::env::env_var; use crate::path_helpers::cwd; use crate::util::set_host_rpath; -use crate::{is_darwin, is_msvc, is_windows, uname}; +use crate::{is_aix, is_darwin, is_msvc, is_windows, uname}; /// Construct a new `rustc` invocation. This will automatically set the library /// search path as `-L cwd()`. Use [`bare_rustc`] to avoid this. @@ -346,7 +346,7 @@ impl Rustc { // endif // endif // ``` - let flag = if is_windows() { + if is_windows() { // So this is a bit hacky: we can't use the DLL version of libstdc++ because // it pulls in the DLL version of libgcc, which means that we end up with 2 // instances of the DW2 unwinding implementation. This is a problem on @@ -362,18 +362,19 @@ impl Rustc { // So we end up with the following hack: we link use static:-bundle to only // link the parts of libstdc++ that we actually use, which doesn't include // the dependency on the pthreads DLL. - if is_msvc() { None } else { Some("-lstatic:-bundle=stdc++") } + if !is_msvc() { + self.cmd.arg("-lstatic:-bundle=stdc++"); + }; } else if is_darwin() { - Some("-lc++") + self.cmd.arg("-lc++"); + } else if is_aix() { + self.cmd.arg("-lc++"); + self.cmd.arg("-lc++abi"); } else { - match &uname()[..] { - "FreeBSD" | "SunOS" | "OpenBSD" => None, - _ => Some("-lstdc++"), - } + if !matches!(&uname()[..], "FreeBSD" | "SunOS" | "OpenBSD") { + self.cmd.arg("-lstdc++"); + }; }; - if let Some(flag) = flag { - self.cmd.arg(flag); - } self } } diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index 5765cb97a7e..6cf0aedfe9f 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -78,7 +78,7 @@ pub use env::{env_var, env_var_os, set_current_dir}; pub use run::{cmd, run, run_fail, run_with_args}; /// Helpers for checking target information. -pub use targets::{is_darwin, is_msvc, is_windows, llvm_components_contain, target, uname, apple_os}; +pub use targets::{is_aix, is_darwin, is_msvc, is_windows, llvm_components_contain, target, uname, apple_os}; /// Helpers for building names of output artifacts that are potentially target-specific. pub use artifact_names::{ diff --git a/src/tools/run-make-support/src/targets.rs b/src/tools/run-make-support/src/targets.rs index 896abb73fc1..ae004fd0cbd 100644 --- a/src/tools/run-make-support/src/targets.rs +++ b/src/tools/run-make-support/src/targets.rs @@ -28,6 +28,12 @@ pub fn is_darwin() -> bool { target().contains("darwin") } +/// Check if target uses AIX. +#[must_use] +pub fn is_aix() -> bool { + target().contains("aix") +} + /// Get the target OS on Apple operating systems. #[must_use] pub fn apple_os() -> &'static str { diff --git a/src/tools/rust-analyzer/.github/workflows/autopublish.yaml b/src/tools/rust-analyzer/.github/workflows/autopublish.yaml index e0135a0269a..5258d9ddd3a 100644 --- a/src/tools/rust-analyzer/.github/workflows/autopublish.yaml +++ b/src/tools/rust-analyzer/.github/workflows/autopublish.yaml @@ -53,7 +53,6 @@ jobs: cargo workspaces rename --from project-model project_model cargo workspaces rename --from test-fixture test_fixture cargo workspaces rename --from test-utils test_utils - cargo workspaces rename --from text-edit text_edit # Remove library crates from the workspaces so we don't auto-publish them as well sed -i 's/ "lib\/\*",//' ./Cargo.toml cargo workspaces rename ra_ap_%n diff --git a/src/tools/rust-analyzer/crates/hir-def/src/data.rs b/src/tools/rust-analyzer/crates/hir-def/src/data.rs index 6d07dc8f9be..2a13f74aac7 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/data.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/data.rs @@ -13,7 +13,6 @@ use syntax::{ast, Parse}; use triomphe::Arc; use crate::{ - attr::Attrs, db::DefDatabase, expander::{Expander, Mark}, item_tree::{self, AssocItem, FnFlags, ItemTree, ItemTreeId, MacroCall, ModItem, TreeId}, @@ -37,8 +36,6 @@ pub struct FunctionData { pub name: Name, pub params: Box<[TypeRefId]>, pub ret_type: TypeRefId, - // FIXME: why are these stored here? They should be accessed via the query - pub attrs: Attrs, pub visibility: RawVisibility, pub abi: Option<Symbol>, pub legacy_const_generics_indices: Option<Box<Box<[u32]>>>, @@ -115,7 +112,6 @@ impl FunctionData { .filter_map(|(_, param)| param.type_ref) .collect(), ret_type: func.ret_type, - attrs: item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()), visibility, abi: func.abi.clone(), legacy_const_generics_indices, diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs index 5c25a55362e..95dfe56ff54 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs @@ -633,6 +633,19 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[ "the `#[rustc_safe_intrinsic]` attribute is used internally to mark intrinsics as safe" ), rustc_attr!( + rustc_intrinsic, Normal, template!(Word), ErrorFollowing, + "the `#[rustc_intrinsic]` attribute is used to declare intrinsics with function bodies", + ), + rustc_attr!( + rustc_no_mir_inline, Normal, template!(Word), WarnFollowing, + "#[rustc_no_mir_inline] prevents the MIR inliner from inlining a function while not affecting codegen" + ), + rustc_attr!( + rustc_intrinsic_must_be_overridden, Normal, template!(Word), ErrorFollowing, + "the `#[rustc_intrinsic_must_be_overridden]` attribute is used to declare intrinsics without real bodies", + ), + + rustc_attr!( rustc_deprecated_safe_2024, Normal, template!(Word), WarnFollowing, "the `#[rustc_safe_intrinsic]` marks functions as unsafe in Rust 2024", ), diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs index 05cd7bd37b4..53795c0b600 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs @@ -381,8 +381,9 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> { TyKind::Error.intern(Interner) } + // object safety was renamed to dyn-compatibility but still remains here in chalk. + // This will be removed since we are going to migrate to next-gen trait solver. fn is_object_safe(&self, trait_id: chalk_ir::TraitId<Interner>) -> bool { - // FIXME: When cargo is updated, change to dyn_compatibility let trait_ = from_chalk_trait_id(trait_id); crate::dyn_compatibility::dyn_compatibility(self.db, trait_).is_none() } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests/intrinsics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests/intrinsics.rs index c5706172b20..c1ac7ae173b 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests/intrinsics.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests/intrinsics.rs @@ -4,9 +4,8 @@ use super::*; fn size_of() { check_number( r#" - extern "rust-intrinsic" { - pub fn size_of<T>() -> usize; - } + #[rustc_intrinsic] + pub fn size_of<T>() -> usize; const GOAL: usize = size_of::<i32>(); "#, @@ -19,9 +18,8 @@ fn size_of_val() { check_number( r#" //- minicore: coerce_unsized - extern "rust-intrinsic" { - pub fn size_of_val<T: ?Sized>(_: *const T) -> usize; - } + #[rustc_intrinsic] + pub fn size_of_val<T: ?Sized>(_: *const T) -> usize; struct X(i32, u8); @@ -32,9 +30,8 @@ fn size_of_val() { check_number( r#" //- minicore: coerce_unsized - extern "rust-intrinsic" { - pub fn size_of_val<T: ?Sized>(_: *const T) -> usize; - } + #[rustc_intrinsic] + pub fn size_of_val<T: ?Sized>(_: *const T) -> usize; const GOAL: usize = { let it: &[i32] = &[1, 2, 3]; @@ -48,9 +45,8 @@ fn size_of_val() { //- minicore: coerce_unsized, transmute use core::mem::transmute; - extern "rust-intrinsic" { - pub fn size_of_val<T: ?Sized>(_: *const T) -> usize; - } + #[rustc_intrinsic] + pub fn size_of_val<T: ?Sized>(_: *const T) -> usize; struct X { x: i64, @@ -70,9 +66,8 @@ fn size_of_val() { //- minicore: coerce_unsized, transmute use core::mem::transmute; - extern "rust-intrinsic" { - pub fn size_of_val<T: ?Sized>(_: *const T) -> usize; - } + #[rustc_intrinsic] + pub fn size_of_val<T: ?Sized>(_: *const T) -> usize; struct X { x: i32, @@ -90,9 +85,8 @@ fn size_of_val() { check_number( r#" //- minicore: coerce_unsized, fmt, builtin_impls, dispatch_from_dyn - extern "rust-intrinsic" { - pub fn size_of_val<T: ?Sized>(_: *const T) -> usize; - } + #[rustc_intrinsic] + pub fn size_of_val<T: ?Sized>(_: *const T) -> usize; const GOAL: usize = { let x: &i16 = &5; @@ -106,9 +100,8 @@ fn size_of_val() { check_number( r#" //- minicore: coerce_unsized - extern "rust-intrinsic" { - pub fn size_of_val<T: ?Sized>(_: *const T) -> usize; - } + #[rustc_intrinsic] + pub fn size_of_val<T: ?Sized>(_: *const T) -> usize; const GOAL: usize = { size_of_val("salam") @@ -123,9 +116,8 @@ fn min_align_of_val() { check_number( r#" //- minicore: coerce_unsized - extern "rust-intrinsic" { - pub fn min_align_of_val<T: ?Sized>(_: *const T) -> usize; - } + #[rustc_intrinsic] + pub fn min_align_of_val<T: ?Sized>(_: *const T) -> usize; struct X(i32, u8); @@ -136,9 +128,8 @@ fn min_align_of_val() { check_number( r#" //- minicore: coerce_unsized - extern "rust-intrinsic" { - pub fn min_align_of_val<T: ?Sized>(_: *const T) -> usize; - } + #[rustc_intrinsic] + pub fn min_align_of_val<T: ?Sized>(_: *const T) -> usize; const GOAL: usize = { let x: &[i32] = &[1, 2, 3]; @@ -153,9 +144,8 @@ fn min_align_of_val() { fn type_name() { check_str( r#" - extern "rust-intrinsic" { - pub fn type_name<T: ?Sized>() -> &'static str; - } + #[rustc_intrinsic] + pub fn type_name<T: ?Sized>() -> &'static str; const GOAL: &str = type_name::<i32>(); "#, @@ -163,9 +153,8 @@ fn type_name() { ); check_str( r#" - extern "rust-intrinsic" { - pub fn type_name<T: ?Sized>() -> &'static str; - } + #[rustc_intrinsic] + pub fn type_name<T: ?Sized>() -> &'static str; mod mod1 { pub mod mod2 { @@ -183,9 +172,8 @@ fn type_name() { fn transmute() { check_number( r#" - extern "rust-intrinsic" { - pub fn transmute<T, U>(e: T) -> U; - } + #[rustc_intrinsic] + pub fn transmute<T, U>(e: T) -> U; const GOAL: i32 = transmute((1i16, 1i16)); "#, @@ -197,10 +185,10 @@ fn transmute() { fn read_via_copy() { check_number( r#" - extern "rust-intrinsic" { - pub fn read_via_copy<T>(e: *const T) -> T; - pub fn volatile_load<T>(e: *const T) -> T; - } + #[rustc_intrinsic] + pub fn read_via_copy<T>(e: *const T) -> T; + #[rustc_intrinsic] + pub fn volatile_load<T>(e: *const T) -> T; const GOAL: i32 = { let x = 2; @@ -399,9 +387,14 @@ fn discriminant_value() { fn likely() { check_number( r#" - extern "rust-intrinsic" { - pub fn likely(b: bool) -> bool; - pub fn unlikely(b: bool) -> bool; + #[rustc_intrinsic] + pub const fn likely(b: bool) -> bool { + b + } + + #[rustc_intrinsic] + pub const fn unlikely(b: bool) -> bool { + b } const GOAL: bool = likely(true) && unlikely(true) && !likely(false) && !unlikely(false); @@ -704,9 +697,8 @@ fn rotate() { ); check_number( r#" - extern "rust-intrinsic" { - pub fn rotate_right<T: Copy>(x: T, y: T) -> T; - } + #[rustc_intrinsic] + pub fn rotate_right<T: Copy>(x: T, y: T) -> T; const GOAL: i32 = rotate_right(10006016, 1020315); "#, @@ -721,9 +713,8 @@ fn simd() { pub struct i8x16( i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8, ); - extern "platform-intrinsic" { - pub fn simd_bitmask<T, U>(x: T) -> U; - } + #[rustc_intrinsic] + pub fn simd_bitmask<T, U>(x: T) -> U; const GOAL: u16 = simd_bitmask(i8x16( 0, 1, 0, 0, 2, 255, 100, 0, 50, 0, 1, 1, 0, 0, 0, 0 )); @@ -735,10 +726,10 @@ fn simd() { pub struct i8x16( i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8, ); - extern "platform-intrinsic" { - pub fn simd_lt<T, U>(x: T, y: T) -> U; - pub fn simd_bitmask<T, U>(x: T) -> U; - } + #[rustc_intrinsic] + pub fn simd_lt<T, U>(x: T, y: T) -> U; + #[rustc_intrinsic] + pub fn simd_bitmask<T, U>(x: T) -> U; const GOAL: u16 = simd_bitmask(simd_lt::<i8x16, i8x16>( i8x16( -105, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs index c9ab0acc084..4991d173b9c 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs @@ -201,7 +201,7 @@ impl<'a> DeclValidator<'a> { // Don't run the lint on extern "[not Rust]" fn items with the // #[no_mangle] attribute. - let no_mangle = data.attrs.by_key(&sym::no_mangle).exists(); + let no_mangle = self.db.attrs(func.into()).by_key(&sym::no_mangle).exists(); if no_mangle && data.abi.as_ref().is_some_and(|abi| *abi != sym::Rust) { cov_mark::hit!(extern_func_no_mangle_ignored); } else { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs index 3d21785a70a..fadf8aca998 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs @@ -472,7 +472,7 @@ fn receiver_is_dispatchable( return false; }; - // `self: Self` can't be dispatched on, but this is already considered dyn compatible + // `self: Self` can't be dispatched on, but this is already considered dyn-compatible // See rustc's comment on https://github.com/rust-lang/rust/blob/3f121b9461cce02a703a0e7e450568849dfaa074/compiler/rustc_trait_selection/src/traits/object_safety.rs#L433-L437 if sig .skip_binders() diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility/tests.rs index 3f3e68eeb1c..8a56bd28b59 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility/tests.rs @@ -66,7 +66,7 @@ fn check_dyn_compatibility<'a>( }); ControlFlow::Continue(()) }); - assert_eq!(osvs, expected, "Dyn Compatibility violations for `{name}` do not match;"); + assert_eq!(osvs, expected, "dyn-compatibility violations for `{name}` do not match;"); } let remains: Vec<_> = expected.keys().collect(); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs index 9c1d8bcf36f..22e7b1d920f 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs @@ -98,7 +98,7 @@ pub use mapping::{ }; pub use method_resolution::check_orphan_rules; pub use traits::TraitEnvironment; -pub use utils::{all_super_traits, is_fn_unsafe_to_call}; +pub use utils::{all_super_traits, direct_super_traits, is_fn_unsafe_to_call}; pub use chalk_ir::{ cast::Cast, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs index 0cdad74a4f6..0a78f4a5b24 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs @@ -9,7 +9,7 @@ use hir_def::{ resolver::HasResolver, }; use hir_expand::name::Name; -use intern::sym; +use intern::{sym, Symbol}; use crate::{ error_lifetime, @@ -54,49 +54,32 @@ impl Evaluator<'_> { } let function_data = self.db.function_data(def); - let is_intrinsic = match &function_data.abi { - Some(abi) => *abi == sym::rust_dash_intrinsic, - None => match def.lookup(self.db.upcast()).container { - hir_def::ItemContainerId::ExternBlockId(block) => { - let id = block.lookup(self.db.upcast()).id; - id.item_tree(self.db.upcast())[id.value].abi.as_ref() - == Some(&sym::rust_dash_intrinsic) - } - _ => false, - }, - }; + let attrs = self.db.attrs(def.into()); + let is_intrinsic = attrs.by_key(&sym::rustc_intrinsic).exists() + // Keep this around for a bit until extern "rustc-intrinsic" abis are no longer used + || (match &function_data.abi { + Some(abi) => *abi == sym::rust_dash_intrinsic, + None => match def.lookup(self.db.upcast()).container { + hir_def::ItemContainerId::ExternBlockId(block) => { + let id = block.lookup(self.db.upcast()).id; + id.item_tree(self.db.upcast())[id.value].abi.as_ref() + == Some(&sym::rust_dash_intrinsic) + } + _ => false, + }, + }); + if is_intrinsic { - self.exec_intrinsic( + return self.exec_intrinsic( function_data.name.as_str(), args, generic_args, destination, locals, span, - )?; - return Ok(true); - } - let is_platform_intrinsic = match &function_data.abi { - Some(abi) => *abi == sym::platform_dash_intrinsic, - None => match def.lookup(self.db.upcast()).container { - hir_def::ItemContainerId::ExternBlockId(block) => { - let id = block.lookup(self.db.upcast()).id; - id.item_tree(self.db.upcast())[id.value].abi.as_ref() - == Some(&sym::platform_dash_intrinsic) - } - _ => false, - }, - }; - if is_platform_intrinsic { - self.exec_platform_intrinsic( - function_data.name.as_str(), - args, - generic_args, - destination, - locals, - span, - )?; - return Ok(true); + !function_data.has_body() + || attrs.by_key(&sym::rustc_intrinsic_must_be_overridden).exists(), + ); } let is_extern_c = match def.lookup(self.db.upcast()).container { hir_def::ItemContainerId::ExternBlockId(block) => { @@ -106,27 +89,25 @@ impl Evaluator<'_> { _ => false, }; if is_extern_c { - self.exec_extern_c( - function_data.name.as_str(), - args, - generic_args, - destination, - locals, - span, - )?; - return Ok(true); + return self + .exec_extern_c( + function_data.name.as_str(), + args, + generic_args, + destination, + locals, + span, + ) + .map(|()| true); } - let alloc_fn = function_data - .attrs - .iter() - .filter_map(|it| it.path().as_ident()) - .map(|it| it.as_str()) - .find(|it| { + + let alloc_fn = + attrs.iter().filter_map(|it| it.path().as_ident()).map(|it| it.symbol()).find(|it| { [ - "rustc_allocator", - "rustc_deallocator", - "rustc_reallocator", - "rustc_allocator_zeroed", + &sym::rustc_allocator, + &sym::rustc_deallocator, + &sym::rustc_reallocator, + &sym::rustc_allocator_zeroed, ] .contains(it) }); @@ -270,12 +251,12 @@ impl Evaluator<'_> { fn exec_alloc_fn( &mut self, - alloc_fn: &str, + alloc_fn: &Symbol, args: &[IntervalAndTy], destination: Interval, ) -> Result<()> { match alloc_fn { - "rustc_allocator_zeroed" | "rustc_allocator" => { + _ if *alloc_fn == sym::rustc_allocator_zeroed || *alloc_fn == sym::rustc_allocator => { let [size, align] = args else { return Err(MirEvalError::InternalError( "rustc_allocator args are not provided".into(), @@ -286,8 +267,8 @@ impl Evaluator<'_> { let result = self.heap_allocate(size, align)?; destination.write_from_bytes(self, &result.to_bytes())?; } - "rustc_deallocator" => { /* no-op for now */ } - "rustc_reallocator" => { + _ if *alloc_fn == sym::rustc_deallocator => { /* no-op for now */ } + _ if *alloc_fn == sym::rustc_reallocator => { let [ptr, old_size, align, new_size] = args else { return Err(MirEvalError::InternalError( "rustc_allocator args are not provided".into(), @@ -603,21 +584,6 @@ impl Evaluator<'_> { } } - fn exec_platform_intrinsic( - &mut self, - name: &str, - args: &[IntervalAndTy], - generic_args: &Substitution, - destination: Interval, - locals: &Locals, - span: MirSpan, - ) -> Result<()> { - if let Some(name) = name.strip_prefix("simd_") { - return self.exec_simd_intrinsic(name, args, generic_args, destination, locals, span); - } - not_supported!("unknown platform intrinsic {name}"); - } - fn exec_intrinsic( &mut self, name: &str, @@ -626,9 +592,17 @@ impl Evaluator<'_> { destination: Interval, locals: &Locals, span: MirSpan, - ) -> Result<()> { + needs_override: bool, + ) -> Result<bool> { if let Some(name) = name.strip_prefix("atomic_") { - return self.exec_atomic_intrinsic(name, args, generic_args, destination, locals, span); + return self + .exec_atomic_intrinsic(name, args, generic_args, destination, locals, span) + .map(|()| true); + } + if let Some(name) = name.strip_prefix("simd_") { + return self + .exec_simd_intrinsic(name, args, generic_args, destination, locals, span) + .map(|()| true); } // FIXME(#17451): Add `f16` and `f128` intrinsics. if let Some(name) = name.strip_suffix("f64") { @@ -701,7 +675,7 @@ impl Evaluator<'_> { } _ => not_supported!("unknown f64 intrinsic {name}"), }; - return destination.write_from_bytes(self, &result.to_le_bytes()); + return destination.write_from_bytes(self, &result.to_le_bytes()).map(|()| true); } if let Some(name) = name.strip_suffix("f32") { let result = match name { @@ -773,7 +747,7 @@ impl Evaluator<'_> { } _ => not_supported!("unknown f32 intrinsic {name}"), }; - return destination.write_from_bytes(self, &result.to_le_bytes()); + return destination.write_from_bytes(self, &result.to_le_bytes()).map(|()| true); } match name { "size_of" => { @@ -1146,12 +1120,6 @@ impl Evaluator<'_> { }; destination.write_from_interval(self, arg.interval) } - "likely" | "unlikely" => { - let [arg] = args else { - return Err(MirEvalError::InternalError("likely arg is not provided".into())); - }; - destination.write_from_interval(self, arg.interval) - } "ctpop" => { let [arg] = args else { return Err(MirEvalError::InternalError("ctpop arg is not provided".into())); @@ -1296,7 +1264,7 @@ impl Evaluator<'_> { None, span, )?; - return Ok(()); + return Ok(true); } } not_supported!("FnOnce was not available for executing const_eval_select"); @@ -1349,8 +1317,10 @@ impl Evaluator<'_> { self.write_memory_using_ref(dst, size)?.fill(val); Ok(()) } - _ => not_supported!("unknown intrinsic {name}"), + _ if needs_override => not_supported!("intrinsic {name} is not implemented"), + _ => return Ok(false), } + .map(|()| true) } fn size_align_of_unsized( diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs index 0a436ff2b41..28bda1e10e5 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs @@ -43,6 +43,17 @@ pub(crate) fn fn_traits( .flat_map(|it| it.as_trait()) } +/// Returns an iterator over the direct super traits (including the trait itself). +pub fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> SmallVec<[TraitId; 4]> { + let mut result = smallvec![trait_]; + direct_super_traits_cb(db, trait_, |tt| { + if !result.contains(&tt) { + result.push(tt); + } + }); + result +} + /// Returns an iterator over the whole super trait hierarchy (including the /// trait itself). pub fn all_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> SmallVec<[TraitId; 4]> { @@ -54,7 +65,7 @@ pub fn all_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> SmallVec<[Trai while let Some(&t) = result.get(i) { // yeah this is quadratic, but trait hierarchies should be flat // enough that this doesn't matter - direct_super_traits(db, t, |tt| { + direct_super_traits_cb(db, t, |tt| { if !result.contains(&tt) { result.push(tt); } @@ -153,7 +164,7 @@ impl Iterator for ClauseElaborator<'_> { } } -fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId, cb: impl FnMut(TraitId)) { +fn direct_super_traits_cb(db: &dyn DefDatabase, trait_: TraitId, cb: impl FnMut(TraitId)) { let resolver = trait_.resolver(db); let generic_params = db.generic_params(trait_.into()); let trait_self = generic_params.trait_self_param(); @@ -259,25 +270,25 @@ pub fn is_fn_unsafe_to_call(db: &dyn HirDatabase, func: FunctionId) -> bool { return true; } + let is_intrinsic = db.attrs(func.into()).by_key(&sym::rustc_intrinsic).exists() + || data.abi.as_ref() == Some(&sym::rust_dash_intrinsic); + let loc = func.lookup(db.upcast()); match loc.container { hir_def::ItemContainerId::ExternBlockId(block) => { - // Function in an `extern` block are always unsafe to call, except when - // it is marked as `safe` or it has `"rust-intrinsic"` ABI there are a - // few exceptions. - let id = block.lookup(db.upcast()).id; - - let is_intrinsic = - id.item_tree(db.upcast())[id.value].abi.as_ref() == Some(&sym::rust_dash_intrinsic); - - if is_intrinsic { + if is_intrinsic || { + let id = block.lookup(db.upcast()).id; + id.item_tree(db.upcast())[id.value].abi.as_ref() == Some(&sym::rust_dash_intrinsic) + } { // Intrinsics are unsafe unless they have the rustc_safe_intrinsic attribute - !data.attrs.by_key(&sym::rustc_safe_intrinsic).exists() + !db.attrs(func.into()).by_key(&sym::rustc_safe_intrinsic).exists() } else { - // Extern items without `safe` modifier are always unsafe + // Function in an `extern` block are always unsafe to call, except when + // it is marked as `safe`. !data.is_safe() } } + _ if is_intrinsic => !db.attrs(func.into()).by_key(&sym::rustc_safe_intrinsic).exists(), _ => false, } } diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index ebd84fd2be2..c9498b3aead 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -68,7 +68,7 @@ use hir_ty::{ all_super_traits, autoderef, check_orphan_rules, consteval::{try_const_usize, unknown_const_as_generic, ConstExt}, diagnostics::BodyValidationDiagnostic, - error_lifetime, known_const_to_ast, + direct_super_traits, error_lifetime, known_const_to_ast, layout::{Layout as TyLayout, RustcEnumVariantIdx, RustcFieldIdx, TagEncoding}, method_resolution, mir::{interpret_mir, MutBorrowKind}, @@ -2246,35 +2246,33 @@ impl Function { /// Does this function have `#[test]` attribute? pub fn is_test(self, db: &dyn HirDatabase) -> bool { - db.function_data(self.id).attrs.is_test() + db.attrs(self.id.into()).is_test() } /// is this a `fn main` or a function with an `export_name` of `main`? pub fn is_main(self, db: &dyn HirDatabase) -> bool { - let data = db.function_data(self.id); - data.attrs.export_name() == Some(&sym::main) - || self.module(db).is_crate_root() && data.name == sym::main + db.attrs(self.id.into()).export_name() == Some(&sym::main) + || self.module(db).is_crate_root() && db.function_data(self.id).name == sym::main } /// Is this a function with an `export_name` of `main`? pub fn exported_main(self, db: &dyn HirDatabase) -> bool { - let data = db.function_data(self.id); - data.attrs.export_name() == Some(&sym::main) + db.attrs(self.id.into()).export_name() == Some(&sym::main) } /// Does this function have the ignore attribute? pub fn is_ignore(self, db: &dyn HirDatabase) -> bool { - db.function_data(self.id).attrs.is_ignore() + db.attrs(self.id.into()).is_ignore() } /// Does this function have `#[bench]` attribute? pub fn is_bench(self, db: &dyn HirDatabase) -> bool { - db.function_data(self.id).attrs.is_bench() + db.attrs(self.id.into()).is_bench() } /// Is this function marked as unstable with `#[feature]` attribute? pub fn is_unstable(self, db: &dyn HirDatabase) -> bool { - db.function_data(self.id).attrs.is_unstable() + db.attrs(self.id.into()).is_unstable() } pub fn is_unsafe_to_call(self, db: &dyn HirDatabase) -> bool { @@ -2289,8 +2287,7 @@ impl Function { } pub fn as_proc_macro(self, db: &dyn HirDatabase) -> Option<Macro> { - let function_data = db.function_data(self.id); - let attrs = &function_data.attrs; + let attrs = db.attrs(self.id.into()); // FIXME: Store this in FunctionData flags? if !(attrs.is_proc_macro() || attrs.is_proc_macro_attribute() @@ -2707,13 +2704,22 @@ impl Trait { db.trait_data(self.id).name.clone() } + pub fn direct_supertraits(self, db: &dyn HirDatabase) -> Vec<Trait> { + let traits = direct_super_traits(db.upcast(), self.into()); + traits.iter().map(|tr| Trait::from(*tr)).collect() + } + + pub fn all_supertraits(self, db: &dyn HirDatabase) -> Vec<Trait> { + let traits = all_super_traits(db.upcast(), self.into()); + traits.iter().map(|tr| Trait::from(*tr)).collect() + } + pub fn items(self, db: &dyn HirDatabase) -> Vec<AssocItem> { db.trait_data(self.id).items.iter().map(|(_name, it)| (*it).into()).collect() } pub fn items_with_supertraits(self, db: &dyn HirDatabase) -> Vec<AssocItem> { - let traits = all_super_traits(db.upcast(), self.into()); - traits.iter().flat_map(|tr| Trait::from(*tr).items(db)).collect() + self.all_supertraits(db).into_iter().flat_map(|tr| tr.items(db)).collect() } pub fn is_auto(self, db: &dyn HirDatabase) -> bool { diff --git a/src/tools/rust-analyzer/crates/ide/src/file_structure.rs b/src/tools/rust-analyzer/crates/ide/src/file_structure.rs index 055080ad17b..5ef65c209ca 100644 --- a/src/tools/rust-analyzer/crates/ide/src/file_structure.rs +++ b/src/tools/rust-analyzer/crates/ide/src/file_structure.rs @@ -19,6 +19,7 @@ pub struct StructureNode { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] pub enum StructureNodeKind { SymbolKind(SymbolKind), + ExternBlock, Region, } @@ -158,6 +159,7 @@ fn structure_node(node: &SyntaxNode) -> Option<StructureNode> { ast::Trait(it) => decl(it, StructureNodeKind::SymbolKind(SymbolKind::Trait)), ast::TraitAlias(it) => decl(it, StructureNodeKind::SymbolKind(SymbolKind::TraitAlias)), ast::Module(it) => decl(it, StructureNodeKind::SymbolKind(SymbolKind::Module)), + ast::Macro(it) => decl(it, StructureNodeKind::SymbolKind(SymbolKind::Macro)), ast::TypeAlias(it) => decl_with_type_ref(&it, it.ty(), StructureNodeKind::SymbolKind(SymbolKind::TypeAlias)), ast::RecordField(it) => decl_with_type_ref(&it, it.ty(), StructureNodeKind::SymbolKind(SymbolKind::Field)), ast::Const(it) => decl_with_type_ref(&it, it.ty(), StructureNodeKind::SymbolKind(SymbolKind::Const)), @@ -205,7 +207,23 @@ fn structure_node(node: &SyntaxNode) -> Option<StructureNode> { Some(node) }, - ast::Macro(it) => decl(it, StructureNodeKind::SymbolKind(SymbolKind::Macro)), + ast::ExternBlock(it) => { + let mut label = "extern".to_owned(); + let abi = it.abi()?; + if let Some(abi) = abi.string_token() { + label.push(' '); + label.push_str(abi.text()); + } + Some(StructureNode { + parent: None, + label, + navigation_range: abi.syntax().text_range(), + node_range: it.syntax().text_range(), + kind: StructureNodeKind::ExternBlock, + detail: None, + deprecated: false, + }) + }, _ => None, } } @@ -327,6 +345,8 @@ fn f() {} fn g() {} } +extern "C" {} + fn let_statements() { let x = 42; let mut y = x; @@ -664,9 +684,18 @@ fn let_statements() { }, StructureNode { parent: None, + label: "extern \"C\"", + navigation_range: 638..648, + node_range: 638..651, + kind: ExternBlock, + detail: None, + deprecated: false, + }, + StructureNode { + parent: None, label: "let_statements", - navigation_range: 641..655, - node_range: 638..798, + navigation_range: 656..670, + node_range: 653..813, kind: SymbolKind( Function, ), @@ -677,11 +706,11 @@ fn let_statements() { }, StructureNode { parent: Some( - 26, + 27, ), label: "x", - navigation_range: 668..669, - node_range: 664..675, + navigation_range: 683..684, + node_range: 679..690, kind: SymbolKind( Local, ), @@ -690,11 +719,11 @@ fn let_statements() { }, StructureNode { parent: Some( - 26, + 27, ), label: "mut y", - navigation_range: 684..689, - node_range: 680..694, + navigation_range: 699..704, + node_range: 695..709, kind: SymbolKind( Local, ), @@ -703,11 +732,11 @@ fn let_statements() { }, StructureNode { parent: Some( - 26, + 27, ), label: "Foo { .. }", - navigation_range: 703..725, - node_range: 699..738, + navigation_range: 718..740, + node_range: 714..753, kind: SymbolKind( Local, ), @@ -716,11 +745,11 @@ fn let_statements() { }, StructureNode { parent: Some( - 26, + 27, ), label: "_", - navigation_range: 788..789, - node_range: 784..796, + navigation_range: 803..804, + node_range: 799..811, kind: SymbolKind( Local, ), diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs index d9ddc2d015b..5a00d635698 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs @@ -1009,10 +1009,10 @@ fn render_dyn_compatibility( safety: Option<DynCompatibilityViolation>, ) { let Some(osv) = safety else { - buf.push_str("Is Dyn compatible"); + buf.push_str("Is dyn-compatible"); return; }; - buf.push_str("Is not Dyn compatible due to "); + buf.push_str("Is not dyn-compatible due to "); match osv { DynCompatibilityViolation::SizedSelf => { buf.push_str("having a `Self: Sized` bound"); @@ -1055,7 +1055,7 @@ fn render_dyn_compatibility( } DynCompatibilityViolation::HasNonCompatibleSuperTrait(super_trait) => { let name = hir::Trait::from(super_trait).name(db); - format_to!(buf, "having a dyn incompatible supertrait `{}`", name.as_str()); + format_to!(buf, "having a dyn-incompatible supertrait `{}`", name.as_str()); } } } diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs index 0ffbf988c35..0986d5542cd 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs @@ -9371,7 +9371,7 @@ trait Compat$0 {} --- - Is Dyn compatible + Is dyn-compatible "#]], ); check( @@ -9393,7 +9393,7 @@ trait UnCompat$0 { --- - Is not Dyn compatible due to having a method `f` that is not dispatchable due to missing a receiver + Is not dyn-compatible due to having a method `f` that is not dispatchable due to missing a receiver "#]], ); check( diff --git a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs index aecafb444c3..865518fe941 100644 --- a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs +++ b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs @@ -392,18 +392,22 @@ define_symbols! { rust_2024, rust_analyzer, Rust, + rustc_allocator_zeroed, + rustc_allocator, rustc_allow_incoherent_impl, rustc_builtin_macro, rustc_coherence_is_core, rustc_const_panic_str, + rustc_deallocator, rustc_deprecated_safe_2024, rustc_has_incoherent_inherent_impls, - rustc_intrinsic, rustc_intrinsic_must_be_overridden, + rustc_intrinsic, rustc_layout_scalar_valid_range_end, rustc_layout_scalar_valid_range_start, rustc_legacy_const_generics, rustc_macro_transparency, + rustc_reallocator, rustc_reservation_impl, rustc_safe_intrinsic, rustc_skip_array_during_method_dispatch, diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs index fa584ab4d21..a5c9d2823e0 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs @@ -1131,7 +1131,7 @@ pub(crate) fn handle_completion_resolve( else { return Ok(original_completion); }; - let resolved_completions = to_proto::completion_items( + let mut resolved_completions = to_proto::completion_items( &snap.config, &forced_resolve_completions_config.fields_to_resolve, &line_index, @@ -1140,15 +1140,13 @@ pub(crate) fn handle_completion_resolve( resolve_data.trigger_character, resolved_completions, ); - let Some(mut resolved_completion) = resolved_completions.into_iter().find(|completion| { - completion.label == original_completion.label - && completion.kind == original_completion.kind - && completion.deprecated == original_completion.deprecated - && completion.preselect == original_completion.preselect - && completion.sort_text == original_completion.sort_text - }) else { - return Ok(original_completion); - }; + + let mut resolved_completion = + if resolved_completions.get(resolve_data.completion_item_index).is_some() { + resolved_completions.swap_remove(resolve_data.completion_item_index) + } else { + return Ok(original_completion); + }; if !resolve_data.imports.is_empty() { let additional_edits = snap diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs index 8039f0644ee..6ddfe118d5e 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs @@ -826,6 +826,7 @@ pub struct CompletionResolveData { pub imports: Vec<CompletionImport>, pub version: Option<i32>, pub trigger_character: Option<char>, + pub completion_item_index: usize, } #[derive(Debug, Serialize, Deserialize)] diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs index d654dc3e7f4..d444f90a131 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs @@ -88,6 +88,7 @@ pub(crate) fn structure_node_kind(kind: StructureNodeKind) -> lsp_types::SymbolK match kind { StructureNodeKind::SymbolKind(symbol) => symbol_kind(symbol), StructureNodeKind::Region => lsp_types::SymbolKind::NAMESPACE, + StructureNodeKind::ExternBlock => lsp_types::SymbolKind::NAMESPACE, } } @@ -391,18 +392,36 @@ fn completion_item( } else { Vec::new() }; - if something_to_resolve || !imports.is_empty() { - let data = lsp_ext::CompletionResolveData { + let (ref_resolve_data, resolve_data) = if something_to_resolve || !imports.is_empty() { + let mut item_index = acc.len(); + let ref_resolve_data = if ref_match.is_some() { + let ref_resolve_data = lsp_ext::CompletionResolveData { + position: tdpp.clone(), + imports: Vec::new(), + version, + trigger_character: completion_trigger_character, + completion_item_index: item_index, + }; + item_index += 1; + Some(to_value(ref_resolve_data).unwrap()) + } else { + None + }; + let resolve_data = lsp_ext::CompletionResolveData { position: tdpp.clone(), imports, version, trigger_character: completion_trigger_character, + completion_item_index: item_index, }; - lsp_item.data = Some(to_value(data).unwrap()); - } + (ref_resolve_data, Some(to_value(resolve_data).unwrap())) + } else { + (None, None) + }; if let Some((label, indel, relevance)) = ref_match { - let mut lsp_item_with_ref = lsp_types::CompletionItem { label, ..lsp_item.clone() }; + let mut lsp_item_with_ref = + lsp_types::CompletionItem { label, data: ref_resolve_data, ..lsp_item.clone() }; lsp_item_with_ref .additional_text_edits .get_or_insert_with(Default::default) @@ -411,6 +430,7 @@ fn completion_item( acc.push(lsp_item_with_ref); }; + lsp_item.data = resolve_data; acc.push(lsp_item); fn set_score( diff --git a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs index 67629fcf7cc..07767d5ae9f 100644 --- a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs +++ b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs @@ -370,15 +370,13 @@ pub mod mem { // endregion:drop // region:transmute - extern "rust-intrinsic" { - pub fn transmute<Src, Dst>(src: Src) -> Dst; - } + #[rustc_intrinsic] + pub fn transmute<Src, Dst>(src: Src) -> Dst; // endregion:transmute // region:size_of - extern "rust-intrinsic" { - pub fn size_of<T>() -> usize; - } + #[rustc_intrinsic] + pub fn size_of<T>() -> usize; // endregion:size_of // region:discriminant diff --git a/src/tools/rust-analyzer/docs/dev/README.md b/src/tools/rust-analyzer/docs/dev/README.md index 12e6d829a08..cd0f49174cd 100644 --- a/src/tools/rust-analyzer/docs/dev/README.md +++ b/src/tools/rust-analyzer/docs/dev/README.md @@ -47,7 +47,7 @@ https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Frust-analyzer Each triaged issue should have one of these labels. * [fun](https://github.com/rust-lang/rust-analyzer/issues?q=is%3Aopen+is%3Aissue+label%3Afun) is for cool, but probably hard stuff. -* [Design](https://github.com/rust-lang/rust-analyzer/issues?q=is%3Aopen+is%3Aissue+label%Design) +* [C-Architecture](https://github.com/rust-lang/rust-analyzer/issues?q=is%3Aissue%20state%3Aopen%20label%3AC-Architecture) is for moderate/large scale architecture discussion. Also a kind of fun. These issues should generally include a link to a Zulip discussion thread. diff --git a/src/tools/rust-analyzer/docs/dev/lsp-extensions.md b/src/tools/rust-analyzer/docs/dev/lsp-extensions.md index 7764f7843a0..b7c536e0279 100644 --- a/src/tools/rust-analyzer/docs/dev/lsp-extensions.md +++ b/src/tools/rust-analyzer/docs/dev/lsp-extensions.md @@ -1,5 +1,5 @@ <!--- -lsp/ext.rs hash: 90cf7718d54fe3c2 +lsp/ext.rs hash: 96f88b7a5d0080c6 If you need to change the above hash to make the test pass, please check if you need to adjust this doc as well and ping this issue: diff --git a/src/tools/rust-analyzer/editors/code/package-lock.json b/src/tools/rust-analyzer/editors/code/package-lock.json index 10b633511d3..6027f813311 100644 --- a/src/tools/rust-analyzer/editors/code/package-lock.json +++ b/src/tools/rust-analyzer/editors/code/package-lock.json @@ -13,12 +13,12 @@ "anser": "^2.1.1", "d3": "^7.8.5", "d3-graphviz": "^5.0.2", - "vscode-languageclient": "^8.1.0" + "vscode-languageclient": "^9.0.1" }, "devDependencies": { "@tsconfig/strictest": "^2.0.1", "@types/node": "~16.11.7", - "@types/vscode": "~1.78.1", + "@types/vscode": "~1.83", "@typescript-eslint/eslint-plugin": "^6.0.0", "@typescript-eslint/parser": "^6.0.0", "@vscode/test-electron": "^2.3.8", @@ -32,7 +32,7 @@ "typescript": "^5.6.0" }, "engines": { - "vscode": "^1.78.0" + "vscode": "^1.83.0" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -880,9 +880,9 @@ "dev": true }, "node_modules/@types/vscode": { - "version": "1.78.1", - "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.78.1.tgz", - "integrity": "sha512-wEA+54axejHu7DhcUfnFBan1IqFD1gBDxAFz8LoX06NbNDMRJv/T6OGthOs52yZccasKfN588EyffHWABkR0fg==", + "version": "1.83.3", + "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.83.3.tgz", + "integrity": "sha512-ZPp5+OQNYrCSFoT4jWOZKdcuXijj+JdN2BJNDhWH4pPbVL6PRQycG9NT8C4a94oul1tFMbkVbXXa9HasI7cLUg==", "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { @@ -5059,24 +5059,24 @@ } }, "node_modules/vscode-jsonrpc": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.1.0.tgz", - "integrity": "sha512-6TDy/abTQk+zDGYazgbIPc+4JoXdwC8NHU9Pbn4UJP1fehUyZmM4RHp5IthX7A6L5KS30PRui+j+tbbMMMafdw==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz", + "integrity": "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==", "engines": { "node": ">=14.0.0" } }, "node_modules/vscode-languageclient": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-8.1.0.tgz", - "integrity": "sha512-GL4QdbYUF/XxQlAsvYWZRV3V34kOkpRlvV60/72ghHfsYFnS/v2MANZ9P6sHmxFcZKOse8O+L9G7Czg0NUWing==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-9.0.1.tgz", + "integrity": "sha512-JZiimVdvimEuHh5olxhxkht09m3JzUGwggb5eRUkzzJhZ2KjCN0nh55VfiED9oez9DyF8/fz1g1iBV3h+0Z2EA==", "dependencies": { "minimatch": "^5.1.0", "semver": "^7.3.7", - "vscode-languageserver-protocol": "3.17.3" + "vscode-languageserver-protocol": "3.17.5" }, "engines": { - "vscode": "^1.67.0" + "vscode": "^1.82.0" } }, "node_modules/vscode-languageclient/node_modules/brace-expansion": { @@ -5099,18 +5099,18 @@ } }, "node_modules/vscode-languageserver-protocol": { - "version": "3.17.3", - "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.3.tgz", - "integrity": "sha512-924/h0AqsMtA5yK22GgMtCYiMdCOtWTSGgUOkgEDX+wk2b0x4sAfLiO4NxBxqbiVtz7K7/1/RgVrVI0NClZwqA==", + "version": "3.17.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz", + "integrity": "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==", "dependencies": { - "vscode-jsonrpc": "8.1.0", - "vscode-languageserver-types": "3.17.3" + "vscode-jsonrpc": "8.2.0", + "vscode-languageserver-types": "3.17.5" } }, "node_modules/vscode-languageserver-types": { - "version": "3.17.3", - "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.3.tgz", - "integrity": "sha512-SYU4z1dL0PyIMd4Vj8YOqFvHu7Hz/enbWtpfnVbJHU4Nd1YNYx8u0ennumc6h48GQNeOLxmwySmnADouT/AuZA==" + "version": "3.17.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz", + "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==" }, "node_modules/which": { "version": "2.0.2", diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json index ccc8c0e3842..b868622b3a5 100644 --- a/src/tools/rust-analyzer/editors/code/package.json +++ b/src/tools/rust-analyzer/editors/code/package.json @@ -27,7 +27,7 @@ } }, "engines": { - "vscode": "^1.78.0" + "vscode": "^1.83.0" }, "enabledApiProposals": [], "scripts": { @@ -49,12 +49,12 @@ "anser": "^2.1.1", "d3": "^7.8.5", "d3-graphviz": "^5.0.2", - "vscode-languageclient": "^8.1.0" + "vscode-languageclient": "^9.0.1" }, "devDependencies": { "@tsconfig/strictest": "^2.0.1", "@types/node": "~16.11.7", - "@types/vscode": "~1.78.1", + "@types/vscode": "~1.83", "@typescript-eslint/eslint-plugin": "^6.0.0", "@typescript-eslint/parser": "^6.0.0", "@vscode/test-electron": "^2.3.8", @@ -490,15 +490,19 @@ "type": "string", "enum": [ "auto", + "llvm-vs-code-extensions.lldb-dap", "vadimcn.vscode-lldb", - "ms-vscode.cpptools" + "ms-vscode.cpptools", + "webfreak.debug" ], "default": "auto", "description": "Preferred debug engine.", "markdownEnumDescriptions": [ - "First try to use [CodeLLDB](https://marketplace.visualstudio.com/items?itemName=vadimcn.vscode-lldb), if it's not installed try to use [MS C++ tools](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools).", + "Use the first available extension out of [LLDB DAP](https://marketplace.visualstudio.com/items?itemName=llvm-vs-code-extensions.lldb-dap), [CodeLLDB](https://marketplace.visualstudio.com/items?itemName=vadimcn.vscode-lldb), [C/C++ for Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools), and [Native Debug](https://marketplace.visualstudio.com/items?itemName=webfreak.debug).", + "Use [LLDB DAP](https://marketplace.visualstudio.com/items?itemName=llvm-vs-code-extensions.lldb-dap)", "Use [CodeLLDB](https://marketplace.visualstudio.com/items?itemName=vadimcn.vscode-lldb)", - "Use [MS C++ tools](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools)" + "Use [C/C++ for Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools)", + "Use [Native Debug](https://marketplace.visualstudio.com/items?itemName=webfreak.debug)" ] }, "rust-analyzer.debug.sourceFileMap": { diff --git a/src/tools/rust-analyzer/editors/code/src/client.ts b/src/tools/rust-analyzer/editors/code/src/client.ts index bf58112916b..eac7b849fdb 100644 --- a/src/tools/rust-analyzer/editors/code/src/client.ts +++ b/src/tools/rust-analyzer/editors/code/src/client.ts @@ -350,6 +350,7 @@ class ExperimentalFeatures implements lc.StaticFeature { _documentSelector: lc.DocumentSelector | undefined, ): void {} dispose(): void {} + clear(): void {} } class OverrideFeatures implements lc.StaticFeature { @@ -369,6 +370,7 @@ class OverrideFeatures implements lc.StaticFeature { _documentSelector: lc.DocumentSelector | undefined, ): void {} dispose(): void {} + clear(): void {} } function isCodeActionWithoutEditsAndCommands(value: any): boolean { diff --git a/src/tools/rust-analyzer/triagebot.toml b/src/tools/rust-analyzer/triagebot.toml index d62adb9144b..1138035d0e8 100644 --- a/src/tools/rust-analyzer/triagebot.toml +++ b/src/tools/rust-analyzer/triagebot.toml @@ -19,3 +19,5 @@ exclude_titles = [ # exclude syncs from subtree in rust-lang/rust "sync from rust", ] labels = ["has-merge-commits", "S-waiting-on-author"] + +[transfer] diff --git a/src/tools/rustbook/.gitignore b/src/tools/rustbook/.gitignore new file mode 100644 index 00000000000..ea8c4bf7f35 --- /dev/null +++ b/src/tools/rustbook/.gitignore @@ -0,0 +1 @@ +/target diff --git a/src/tools/rustbook/Cargo.lock b/src/tools/rustbook/Cargo.lock index 27ccb205b50..9e549348da3 100644 --- a/src/tools/rustbook/Cargo.lock +++ b/src/tools/rustbook/Cargo.lock @@ -47,9 +47,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.15" +version = "0.6.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" +checksum = "23a1e53f0f5d86382dafe1cf314783b2044280f406e7e1506368220ad11b1338" dependencies = [ "anstyle", "anstyle-parse", @@ -62,43 +62,43 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.8" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" [[package]] name = "anstyle-parse" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.4" +version = "3.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" +checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" dependencies = [ "anstyle", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "anyhow" -version = "1.0.89" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" +checksum = "74f37166d7d48a0284b99dd824694c26119c700b53bf0d1540cdb147dbdaaf13" [[package]] name = "autocfg" @@ -161,9 +161,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "cc" -version = "1.1.22" +version = "1.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9540e661f81799159abee814118cc139a2004b3a3aa3ea37724a1b66530b90e0" +checksum = "67b9470d453346108f93a59222a9a1a5724db32d0a4727b7ab7ace4b4d822dc9" dependencies = [ "shlex", ] @@ -185,14 +185,14 @@ dependencies = [ "js-sys", "num-traits", "wasm-bindgen", - "windows-targets 0.52.6", + "windows-targets", ] [[package]] name = "clap" -version = "4.5.18" +version = "4.5.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0956a43b323ac1afaffc053ed5c4b7c1f1800bacd1683c353aabbb752515dd3" +checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8" dependencies = [ "clap_builder", "clap_derive", @@ -200,9 +200,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.18" +version = "4.5.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d72166dd41634086d5803a47eb71ae740e61d84709c36f3c34110173db3961b" +checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54" dependencies = [ "anstream", "anstyle", @@ -213,9 +213,9 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.5.29" +version = "4.5.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8937760c3f4c60871870b8c3ee5f9b30771f792a7045c48bcbba999d7d6b3b8e" +checksum = "86bc73de94bc81e52f3bebec71bc4463e9748f7a59166663e32044669577b0e2" dependencies = [ "clap", ] @@ -240,9 +240,9 @@ checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" [[package]] name = "colorchoice" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] name = "core-foundation-sys" @@ -441,11 +441,12 @@ dependencies = [ [[package]] name = "handlebars" -version = "5.1.2" +version = "6.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d08485b96a0e6393e9e4d1b8d48cf74ad6c063cd905eb33f42c1ce3f0377539b" +checksum = "fd4ccde012831f9a071a637b0d4e31df31c0f6c525784b35ae76a9ac6bc1e315" dependencies = [ "log", + "num-order", "pest", "pest_derive", "serde", @@ -455,9 +456,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.14.5" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" [[package]] name = "heck" @@ -535,9 +536,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" +checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" dependencies = [ "equivalent", "hashbrown", @@ -557,9 +558,9 @@ checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "js-sys" -version = "0.3.70" +version = "0.3.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" +checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" dependencies = [ "wasm-bindgen", ] @@ -572,9 +573,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.159" +version = "0.2.161" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" +checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" [[package]] name = "libdbus-sys" @@ -645,9 +646,9 @@ dependencies = [ [[package]] name = "mdbook" -version = "0.4.40" +version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b45a38e19bd200220ef07c892b0157ad3d2365e5b5a267ca01ad12182491eea5" +checksum = "7624879735513024d323e7267a0b3a7176aceb0db537939beb4ee31d9e8945e3" dependencies = [ "ammonia", "anyhow", @@ -763,6 +764,21 @@ dependencies = [ ] [[package]] +name = "num-modular" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17bb261bf36fa7d83f4c294f834e91256769097b3cb505d44831e0a179ac647f" + +[[package]] +name = "num-order" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "537b596b97c40fcf8056d153049eb22f481c17ebce72a513ec9286e4986d1bb6" +dependencies = [ + "num-modular", +] + +[[package]] name = "num-traits" version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -773,9 +789,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.19.0" +version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "onig" @@ -831,14 +847,14 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-targets 0.52.6", + "windows-targets", ] [[package]] name = "pathdiff" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" +checksum = "d61c5ce1153ab5b689d0c074c4e7fc613e942dfb7dd9eea5ab202d2ad91fe361" [[package]] name = "percent-encoding" @@ -848,9 +864,9 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pest" -version = "2.7.13" +version = "2.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdbef9d1d47087a895abd220ed25eb4ad973a5e26f6a4367b038c25e28dfc2d9" +checksum = "879952a81a83930934cbf1786752d6dedc3b1f29e8f8fb2ad1d0a36f377cf442" dependencies = [ "memchr", "thiserror", @@ -859,9 +875,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.7.13" +version = "2.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d3a6e3394ec80feb3b6393c725571754c6188490265c61aaf260810d6b95aa0" +checksum = "d214365f632b123a47fd913301e14c946c61d1c183ee245fa76eb752e59a02dd" dependencies = [ "pest", "pest_generator", @@ -869,9 +885,9 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.13" +version = "2.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94429506bde1ca69d1b5601962c73f4172ab4726571a59ea95931218cb0e930e" +checksum = "eb55586734301717aea2ac313f50b2eb8f60d2fc3dc01d190eefa2e625f60c4e" dependencies = [ "pest", "pest_meta", @@ -882,9 +898,9 @@ dependencies = [ [[package]] name = "pest_meta" -version = "2.7.13" +version = "2.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac8a071862e93690b6e34e9a5fb8e33ff3734473ac0245b27232222c4906a33f" +checksum = "b75da2a70cf4d9cb76833c990ac9cd3923c9a8905a8929789ce347c84564d03d" dependencies = [ "once_cell", "pest", @@ -980,9 +996,9 @@ checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" dependencies = [ "unicode-ident", ] @@ -1083,18 +1099,18 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.6" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "355ae415ccd3a04315d3f8246e86d67689ea74d88d915576e1589a351062a13b" +checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" dependencies = [ "bitflags 2.6.0", ] [[package]] name = "regex" -version = "1.10.6" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", @@ -1104,9 +1120,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" dependencies = [ "aho-corasick", "memchr", @@ -1115,9 +1131,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "rustbook" @@ -1134,9 +1150,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.37" +version = "0.38.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" +checksum = "aa260229e6538e52293eeb577aabd09945a09d6d9cc0fc550ed7529056c2e32a" dependencies = [ "bitflags 2.6.0", "errno", @@ -1174,18 +1190,18 @@ checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" [[package]] name = "serde" -version = "1.0.210" +version = "1.0.214" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" +checksum = "f55c3193aca71c12ad7890f1785d2b73e1b9f63a0bbc353c08ef26fe03fc56b5" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.210" +version = "1.0.214" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" +checksum = "de523f781f095e28fa605cdce0f8307e451cc0fd14e2eb4cd2e98a355b147766" dependencies = [ "proc-macro2", "quote", @@ -1194,9 +1210,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.128" +version = "1.0.132" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" +checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" dependencies = [ "itoa", "memchr", @@ -1276,9 +1292,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.79" +version = "2.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" +checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" dependencies = [ "proc-macro2", "quote", @@ -1331,12 +1347,12 @@ dependencies = [ [[package]] name = "terminal_size" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7" +checksum = "4f599bd7ca042cfdf8f4512b277c02ba102247820f9d9d4a9f521f496751a6ef" dependencies = [ "rustix", - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] @@ -1347,18 +1363,18 @@ checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" [[package]] name = "thiserror" -version = "1.0.64" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" +checksum = "5d171f59dbaa811dbbb1aee1e73db92ec2b122911a48e1390dfe327a821ddede" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.64" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" +checksum = "b08be0f17bd307950653ce45db00cd31200d82b624b36e181337d9c7d92765b5" dependencies = [ "proc-macro2", "quote", @@ -1437,24 +1453,21 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "ucd-trie" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" [[package]] name = "unicase" -version = "2.7.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" -dependencies = [ - "version_check", -] +checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df" [[package]] name = "unicode-bidi" -version = "0.3.15" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" +checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893" [[package]] name = "unicode-ident" @@ -1524,9 +1537,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" +checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" dependencies = [ "cfg-if", "once_cell", @@ -1535,9 +1548,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" +checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" dependencies = [ "bumpalo", "log", @@ -1550,9 +1563,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" +checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1560,9 +1573,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" +checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" dependencies = [ "proc-macro2", "quote", @@ -1573,9 +1586,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" +checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" [[package]] name = "winapi" @@ -1614,16 +1627,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", + "windows-targets", ] [[package]] @@ -1632,7 +1636,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -1641,22 +1645,7 @@ version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", + "windows-targets", ] [[package]] @@ -1665,48 +1654,30 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", "windows_i686_gnullvm", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - -[[package]] -name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - -[[package]] -name = "windows_i686_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" @@ -1719,48 +1690,24 @@ checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[package]] -name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - -[[package]] -name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - -[[package]] -name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - -[[package]] -name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" diff --git a/src/tools/rustdoc-gui-test/Cargo.toml b/src/tools/rustdoc-gui-test/Cargo.toml index 4cb200ebc7c..f7384a98f85 100644 --- a/src/tools/rustdoc-gui-test/Cargo.toml +++ b/src/tools/rustdoc-gui-test/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] -build_helper = { path = "../build_helper" } +build_helper = { path = "../../build_helper" } compiletest = { path = "../compiletest" } getopts = "0.2" walkdir = "2" diff --git a/src/tools/rustdoc-js/tester.js b/src/tools/rustdoc-js/tester.js index e162ba033cc..7aa5e102e6d 100644 --- a/src/tools/rustdoc-js/tester.js +++ b/src/tools/rustdoc-js/tester.js @@ -2,6 +2,14 @@ const fs = require("fs"); const path = require("path"); + +function arrayToCode(array) { + return array.map((value, index) => { + value = value.split(" ").join(" "); + return (index % 2 === 1) ? ("`" + value + "`") : value; + }).join(""); +} + function loadContent(content) { const Module = module.constructor; const m = new Module(); @@ -84,7 +92,6 @@ function checkNeededFields(fullPath, expected, error_text, queryName, position) if (fullPath.length === 0) { fieldsToCheck = [ "foundElems", - "original", "returned", "userQuery", "error", @@ -181,15 +188,7 @@ function valueCheck(fullPath, expected, result, error_text, queryName) { if (!result_v.forEach) { throw result_v; } - result_v.forEach((value, index) => { - value = value.split(" ").join(" "); - if (index % 2 === 1) { - result_v[index] = "`" + value + "`"; - } else { - result_v[index] = value; - } - }); - result_v = result_v.join(""); + result_v = arrayToCode(result_v); } const obj_path = fullPath + (fullPath.length > 0 ? "." : "") + key; valueCheck(obj_path, expected[key], result_v, error_text, queryName); @@ -437,9 +436,41 @@ function loadSearchJS(doc_folder, resource_suffix) { searchModule.initSearch(searchIndex.searchIndex); const docSearch = searchModule.docSearch; return { - doSearch: function(queryStr, filterCrate, currentCrate) { - return docSearch.execQuery(searchModule.parseQuery(queryStr), + doSearch: async function(queryStr, filterCrate, currentCrate) { + const result = await docSearch.execQuery(searchModule.parseQuery(queryStr), filterCrate, currentCrate); + for (const tab in result) { + if (!Object.prototype.hasOwnProperty.call(result, tab)) { + continue; + } + if (!(result[tab] instanceof Array)) { + continue; + } + for (const entry of result[tab]) { + for (const key in entry) { + if (!Object.prototype.hasOwnProperty.call(entry, key)) { + continue; + } + if (key === "displayTypeSignature") { + const {type, mappedNames, whereClause} = + await entry.displayTypeSignature; + entry.displayType = arrayToCode(type); + entry.displayMappedNames = [...mappedNames.entries()] + .map(([name, qname]) => { + return `${name} = ${qname}`; + }).join(", "); + entry.displayWhereClause = [...whereClause.entries()] + .flatMap(([name, value]) => { + if (value.length === 0) { + return []; + } + return [`${name}: ${arrayToCode(value)}`]; + }).join(", "); + } + } + } + } + return result; }, getCorrections: function(queryStr, filterCrate, currentCrate) { const parsedQuery = searchModule.parseQuery(queryStr); diff --git a/src/tools/suggest-tests/Cargo.toml b/src/tools/suggest-tests/Cargo.toml index 7c048d53a50..d6f86078d7e 100644 --- a/src/tools/suggest-tests/Cargo.toml +++ b/src/tools/suggest-tests/Cargo.toml @@ -5,4 +5,4 @@ edition = "2021" [dependencies] glob = "0.3.0" -build_helper = { version = "0.1.0", path = "../build_helper" } +build_helper = { version = "0.1.0", path = "../../build_helper" } diff --git a/src/tools/tidy/Cargo.toml b/src/tools/tidy/Cargo.toml index 42e608ff5ce..bc75787fb1a 100644 --- a/src/tools/tidy/Cargo.toml +++ b/src/tools/tidy/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" autobins = false [dependencies] -build_helper = { path = "../build_helper" } +build_helper = { path = "../../build_helper" } cargo_metadata = "0.18" regex = "1" miropt-test-tools = { path = "../miropt-test-tools" } diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 8e12db409ec..e065f01ebba 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -24,6 +24,7 @@ const LICENSES: &[&str] = &[ "BSD-2-Clause OR Apache-2.0 OR MIT", // zerocopy "ISC", "MIT / Apache-2.0", + "MIT AND (MIT OR Apache-2.0)", "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)", // compiler-builtins "MIT OR Apache-2.0 OR LGPL-2.1-or-later", // r-efi, r-efi-alloc "MIT OR Apache-2.0 OR Zlib", // tinyvec_macros @@ -92,6 +93,7 @@ const EXCEPTIONS: ExceptionList = &[ ("constant_time_eq", "CC0-1.0 OR MIT-0 OR Apache-2.0"), // rustc ("dissimilar", "Apache-2.0"), // rustdoc, rustc_lexer (few tests) via expect-test, (dev deps) ("fluent-langneg", "Apache-2.0"), // rustc (fluent translations) + ("foldhash", "Zlib"), // rustc ("instant", "BSD-3-Clause"), // rustc_driver/tracing-subscriber/parking_lot ("mdbook", "MPL-2.0"), // mdbook ("option-ext", "MPL-2.0"), // cargo-miri (via `directories`) @@ -283,6 +285,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "fluent-langneg", "fluent-syntax", "fnv", + "foldhash", "generic-array", "getopts", "getrandom", diff --git a/src/tools/tidy/src/known_bug.rs b/src/tools/tidy/src/known_bug.rs index 182a81c6ec9..a8771654144 100644 --- a/src/tools/tidy/src/known_bug.rs +++ b/src/tools/tidy/src/known_bug.rs @@ -6,8 +6,22 @@ use crate::walk::*; pub fn check(filepath: &Path, bad: &mut bool) { walk(filepath, |path, _is_dir| filter_not_rust(path), &mut |entry, contents| { - let file = entry.path(); - if !contents.lines().any(|line| line.starts_with("//@ known-bug: ")) { + let file: &Path = entry.path(); + + // files in "auxiliary" do not need to crash by themselves + let test_path_segments = + file.iter().map(|s| s.to_string_lossy().into()).collect::<Vec<String>>(); + let test_path_segments_str = + test_path_segments.iter().map(|s| s.as_str()).collect::<Vec<&str>>(); + + if !matches!(test_path_segments_str[..], [ + .., + "tests", + "crashes", + "auxiliary", + _aux_file_rs + ]) && !contents.lines().any(|line| line.starts_with("//@ known-bug: ")) + { tidy_error!( bad, "{} crash/ice test does not have a \"//@ known-bug: \" directive", diff --git a/src/tools/unicode-table-generator/src/range_search.rs b/src/tools/unicode-table-generator/src/range_search.rs index 9a51979a2f0..14da876eda7 100644 --- a/src/tools/unicode-table-generator/src/range_search.rs +++ b/src/tools/unicode-table-generator/src/range_search.rs @@ -1,4 +1,5 @@ #[inline(always)] +#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_unicode_case_lookup", since = "1.84.0"))] const fn bitset_search< const N: usize, const CHUNK_SIZE: usize, diff --git a/src/tools/unicode-table-generator/src/raw_emitter.rs b/src/tools/unicode-table-generator/src/raw_emitter.rs index 46010692fe5..dd064c59283 100644 --- a/src/tools/unicode-table-generator/src/raw_emitter.rs +++ b/src/tools/unicode-table-generator/src/raw_emitter.rs @@ -97,6 +97,10 @@ impl RawEmitter { self.blank_line(); + writeln!( + &mut self.file, + r#"#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_unicode_case_lookup", since = "1.84.0"))]"# + ).unwrap(); writeln!(&mut self.file, "pub const fn lookup(c: char) -> bool {{").unwrap(); if first_code_point > 0x7f { writeln!(&mut self.file, " (c as u32) >= {first_code_point:#04x} &&").unwrap(); |
